dagger/dagger · error
structural input ref cannot have both result and digest
Error message
structural input ref cannot have both result and digest
What it means
Returned by ResultCallStructuralInputRef.Validate when the ref has both a Result pointer and a Digest set. A structural input identifies an input either by live result reference or by digest; specifying both is contradictory and rejected by this validation guard.
Source
Thrown at dagql/result_call_frame.go:1012
}
return "", nil, fmt.Errorf("result call frame %q structural inputs: %w", field, err)
}
}
return digest.Digest(h.DigestAndClose()), inputRefs, nil
}
func (frame *ResultCall) AllEffectIDs() ([]string, error) {
// FIXME: effect IDs are currently broken and only feed telemetry. Re-implement
// them properly before restoring recursive effect traversal over result-call
// refs and inputs.
return []string{}, nil
}
func (ref ResultCallStructuralInputRef) Validate() error {
switch {
case ref.Result != nil && ref.Digest != "":
return fmt.Errorf("structural input ref cannot have both result and digest")
case ref.Result != nil:
return ref.Result.Validate()
case ref.Result == nil && ref.Digest == "":
return fmt.Errorf("structural input ref must have either result or digest")
default:
return nil
}
}
func (ref ResultCallStructuralInputRef) InputDigest(ctx context.Context) (digest.Digest, error) {
c, err := EngineCache(ctx)
if err != nil {
return "", err
}
return ref.inputDigest(c)
}
func (ref ResultCallStructuralInputRef) inputDigest(c *Cache) (digest.Digest, error) {View on GitHub (pinned to 82ba2681db)
Solutions
- Set only Result (the digest is computed on demand) or only Digest, never both
- Clear the Digest field when a Result is available, or vice versa
- Prefer constructing via a helper constructor that enforces mutual exclusion
Example fix
// before
ref := ResultCallStructuralInputRef{Result: r, Digest: d}
// after
ref := ResultCallStructuralInputRef{Result: r} Defensive patterns
Strategy: validation
Validate before calling
if ref.Result != nil && ref.Digest != "" {
return fmt.Errorf("choose either Result or Digest, not both")
} Type guard
func hasExactlyOneSource(ref ResultCallStructuralInputRef) bool {
return (ref.Result != nil) != (ref.Digest != "")
} Prevention
- Never set both fields in struct literals
- Use a NewStructuralInputRef constructor
- When Result is available, omit Digest
When it happens
Trigger: Constructing ResultCallStructuralInputRef{Result: r, Digest: d} with both fields non-zero, then calling Validate().
Common situations: Merging two code paths (one that used result refs, one that used digests) and combining fields; copy/paste construction that sets both for 'safety'.
Related errors
- result ref cannot have both result ID and call
- result call frame %q structural inputs: %w
- structural input ref must have either result or digest
- missing result ref
- before ID: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/02183a9ba01d83a3.
Report an issue: GitHub.