#Error type not showing up in module function signature

1 messages · Page 1 of 1 (latest)

humble zinc
#

Hello! I have a module I'm working on where the error in some function returns isn't showing up in function signatures when trying to call functions from a test module. I've narrowed down a reproducible segment of the code to the below (the module is named debian). Any idea what I might be doing wrong?

// File used to store the Debian snapshot time
const (
    SNAPSHOT_FILE string = "DEBIAN_SNAPSHOT"
)

// Entrypoint for Dagger module
type Debian struct {
    // Metadata directory
    MetadataDir *dagger.Directory
}

func New(
    // +optional
    metadataDir *dagger.Directory,
) *Debian {
    return &Debian{
        MetadataDir: metadataDir,
    }
}

func (m *Debian) NewDebianBuilder(ctx context.Context) (*DebianImageBuilder, error) {
    exists, err := m.MetadataDir.Exists(ctx, SNAPSHOT_FILE)
    if err != nil {
        return nil, err
    }

    if exists {
        return newDebianImageBuilder(m.MetadataDir.File(SNAPSHOT_FILE)), nil
    }
    return newDebianImageBuilder(nil), nil
}


// Builder object used to create Debian-based images. Currently only supports Debian proper, not Ubuntu
type DebianImageBuilder struct {
    // This points to a file that contains the default snapshot time to use if an explicit timestamp is not provided
    // +private
    SnapshotFile *dagger.File

    // Which major version of Debian to use for the image
    DebVersion int

    // An explicit timestamp to use for all apt operations. If not provided the SnapshotFile will be read
    // +private
    providedSnapshotTime string

    // Whether or not to use the distroless variant of the specific Debian version. Note, distroless is only available for released versions and only for the most recent two major versions
    // +private
    isDistroless bool
}

func newDebianImageBuilder(
    SnapshotFile *dagger.File,
) *DebianImageBuilder {
    return &DebianImageBuilder{
        SnapshotFile: SnapshotFile,
        DebVersion:   getDefaultDebianVersion(),
    }
}
#

From the test module I can see that the code generated is:

func (r *Debian) NewDebianBuilder() *DebianImageBuilder { // debian (../../../../../../.dagger/modules/debian/main.go:23:1)
    q := r.query.Select("newDebianBuilder")

    return &DebianImageBuilder{
        query: q,
    }
}
prisma olive
#

@humble zinc this is because the Go SDK (on the client side) is opinionated about laziness and errors. Basically:

  • For any function that returns an object, the Go SDK will generate a lazy client binding: calling this binding does not actually send an API request. Hence the lack of error return. This is because in the underlying graphql language, you can't actually query an object: you have to query at least one scalar field within it. Since the API query is not complete, nothing can be sent.

  • For any function that returns a non-object type (scalar, array etc), the Go SDK will generate a client binding that actually sends the API query - and therefore can return an error.

This is orthogonal to the server-side code (your function). Eventually your function will be called, and if it returns an error, that error will be received by the client. The only question is when.

#

sorry @woven urchin I accidentally tagged you in that response! Typo

humble zinc
#

Or how do I force execution so I can check errors?

prisma olive
# humble zinc So if I understand you correctly I need to follow this through to syncing whatev...

I guess it depends what you're trying to achieve. By design Dagger errs on the side of laziness, to never force execution when you don't need it. The tradeoff is that occasionally, one can be taken aback by getting more laziness than execpted - like you are right now 🙂

Now the question is - besides the initial surprise, is the laziness actually getting in the way? If so, let's find the best fix.