{"record":{"id":"bec11dd8a44a8abc","repo":"dagger/dagger","slug":"invalid-json-string","errorCode":null,"errorMessage":"invalid JSON string","messagePattern":"invalid JSON string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dagql/call/id.go","lineNumber":591,"sourceCode":"\tproto, err := proto.MarshalOptions{Deterministic: true}.MarshalAppend(buf, dagPB)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to marshal ID proto: %w\", err)\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(proto), nil\n}\n\nfunc (id *ID) MarshalJSON() ([]byte, error) {\n\tenc, err := id.Encode()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn []byte(`\"` + enc + `\"`), nil\n}\n\nfunc (id *ID) UnmarshalJSON(data []byte) error {\n\tif len(data) < 2 || data[0] != '\"' || data[len(data)-1] != '\"' {\n\t\treturn fmt.Errorf(\"invalid JSON string\")\n\t}\n\tenc := string(data[1 : len(data)-1])\n\treturn id.Decode(enc)\n}\n\n// NOTE: use with caution, any mutations to the returned proto can corrupt the ID\nfunc (id *ID) ToProto() (*callpbv1.DAG, error) {\n\tif id == nil {\n\t\treturn &callpbv1.DAG{}, nil\n\t}\n\tif id.mode == idModeHandle {\n\t\tif id.typ == nil {\n\t\t\treturn nil, fmt.Errorf(\"handle-form ID missing type\")\n\t\t}\n\t\treturn &callpbv1.DAG{\n\t\t\tValue: &callpbv1.DAG_EngineResult{\n\t\t\t\tEngineResult: &callpbv1.EngineResultRef{\n\t\t\t\t\tResultID: id.engineResultID,","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/dagql/call/id.go#L573-L609","documentation":"ID.UnmarshalJSON rejects any JSON payload that is not a quoted string (minimum 2 chars, starting and ending with a double quote). The library throws this because a Dagger ID must be a base64-encoded DAG proto serialized as a JSON string; non-string JSON (numbers, objects, null, or empty input) cannot be decoded.","triggerScenarios":"Unmarshaling JSON into dagql/call.ID when the JSON field is not a quoted string — e.g. null, a number, an object/array, or a zero-length/one-char buffer.","commonSituations":"Feeding hand-crafted or partially serialized JSON into an ID field; a GraphQL/server layer sending null instead of a string ID; tests or clients constructing IDs incorrectly; schema drift where an ID field became nullable.","solutions":["Ensure the JSON value for the ID field is a double-quoted base64 string, e.g. \"dAG...\"","Coerce or guard nulls before unmarshaling: only call json.Unmarshal on payloads where the ID field is a string","If the value may be absent, use a *ID (pointer) or json.RawMessage and unmarshal conditionally","Verify the producer is serializing the ID via ID.MarshalJSON (which quotes it) and not writing raw bytes"],"exampleFix":"// before\ndata := []byte(`{\"id\": null}`)\nvar v struct{ ID dagql.ID }\njson.Unmarshal(data, &v) // error: invalid JSON string\n\n// after\ndata := []byte(`{\"id\": \"<base64-id>\"}`)\nvar v struct{ ID dagql.ID }\nif err := json.Unmarshal(data, &v); err != nil { /* handle */ }","handlingStrategy":"validation","validationCode":"func validJSONStringID(b []byte) bool {\n\treturn len(b) >= 2 && b[0] == '\"' && b[len(b)-1] == '\"'\n}","typeGuard":"func isQuotedJSON(s string) bool {\n\tvar str string\n\treturn json.Unmarshal([]byte(s), &str) == nil\n}","tryCatchPattern":"var id dagql.ID\nif err := json.Unmarshal(data, &id); err != nil {\n\tif strings.Contains(err.Error(), \"invalid JSON string\") {\n\t\t// payload's id field is not a string; handle fallback\n\t}\n\treturn err\n}","preventionTips":["Always serialize IDs through ID.MarshalJSON so they are quoted","Use *ID for optional ID fields so null decodes without error","Validate payloads with a schema that requires ID fields to be strings","Roundtrip-test IDs (Encode -> Decode) in CI"],"tags":["json","deserialization","dagql"],"backgroundTag":"invalid-json-type","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"}