{"record":{"id":"02183a9ba01d83a3","repo":"dagger/dagger","slug":"structural-input-ref-cannot-have-both-result-and-d","errorCode":null,"errorMessage":"structural input ref cannot have both result and digest","messagePattern":"structural input ref cannot have both result and digest","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dagql/result_call_frame.go","lineNumber":1012,"sourceCode":"\t\t\t}\n\t\t\treturn \"\", nil, fmt.Errorf(\"result call frame %q structural inputs: %w\", field, err)\n\t\t}\n\t}\n\n\treturn digest.Digest(h.DigestAndClose()), inputRefs, nil\n}\n\nfunc (frame *ResultCall) AllEffectIDs() ([]string, error) {\n\t// FIXME: effect IDs are currently broken and only feed telemetry. Re-implement\n\t// them properly before restoring recursive effect traversal over result-call\n\t// refs and inputs.\n\treturn []string{}, nil\n}\n\nfunc (ref ResultCallStructuralInputRef) Validate() error {\n\tswitch {\n\tcase ref.Result != nil && ref.Digest != \"\":\n\t\treturn fmt.Errorf(\"structural input ref cannot have both result and digest\")\n\tcase ref.Result != nil:\n\t\treturn ref.Result.Validate()\n\tcase ref.Result == nil && ref.Digest == \"\":\n\t\treturn fmt.Errorf(\"structural input ref must have either result or digest\")\n\tdefault:\n\t\treturn nil\n\t}\n}\n\nfunc (ref ResultCallStructuralInputRef) InputDigest(ctx context.Context) (digest.Digest, error) {\n\tc, err := EngineCache(ctx)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn ref.inputDigest(c)\n}\n\nfunc (ref ResultCallStructuralInputRef) inputDigest(c *Cache) (digest.Digest, error) {","sourceCodeStart":994,"sourceCodeEnd":1030,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/dagql/result_call_frame.go#L994-L1030","documentation":"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.","triggerScenarios":"Constructing ResultCallStructuralInputRef{Result: r, Digest: d} with both fields non-zero, then calling Validate().","commonSituations":"Merging two code paths (one that used result refs, one that used digests) and combining fields; copy/paste construction that sets both for 'safety'.","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"],"exampleFix":"// before\nref := ResultCallStructuralInputRef{Result: r, Digest: d}\n// after\nref := ResultCallStructuralInputRef{Result: r}","handlingStrategy":"validation","validationCode":"if ref.Result != nil && ref.Digest != \"\" {\n    return fmt.Errorf(\"choose either Result or Digest, not both\")\n}","typeGuard":"func hasExactlyOneSource(ref ResultCallStructuralInputRef) bool {\n    return (ref.Result != nil) != (ref.Digest != \"\")\n}","tryCatchPattern":null,"preventionTips":["Never set both fields in struct literals","Use a NewStructuralInputRef constructor","When Result is available, omit Digest"],"tags":["go","dagql","validation","mutually-exclusive"],"backgroundTag":"structural-input-validation-failed","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}