{"record":{"id":"f292ed9bae31d2fb","repo":"dagger/dagger","slug":"unmarshal-sdk-as-struct-w","errorCode":null,"errorMessage":"unmarshal sdk as struct: %w","messagePattern":"unmarshal sdk as struct: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/modules/config.go","lineNumber":262,"sourceCode":"\tif len(data) == 0 {\n\t\tsdk.Source = \"\"\n\t\treturn nil\n\t}\n\n\t// check if this is a legacy config, where sdk was a string\n\tif data[0] == '\"' {\n\t\tvar sdkRefStr string\n\t\tif err := json.Unmarshal(data, &sdkRefStr); err != nil {\n\t\t\treturn fmt.Errorf(\"unmarshal sdk as string: %w\", err)\n\t\t}\n\t\t*sdk = SDK{Source: sdkRefStr}\n\t\treturn nil\n\t}\n\n\ttype alias SDK // lets us use the default json unmashaler\n\tvar tmp alias\n\tif err := json.Unmarshal(data, &tmp); err != nil {\n\t\treturn fmt.Errorf(\"unmarshal sdk as struct: %w\", err)\n\t}\n\t*sdk = SDK(tmp)\n\treturn nil\n}\n\nfunc (modCfg *ModuleConfig) UnmarshalJSON(data []byte) error {\n\tif modCfg == nil {\n\t\treturn fmt.Errorf(\"cannot unmarshal into nil %T\", modCfg)\n\t}\n\tif len(data) == 0 {\n\t\treturn nil\n\t}\n\n\ttype alias ModuleConfig // lets us use the default json unmashaler\n\tvar tmp struct {\n\t\talias\n\t\tRuntime *SDK `json:\"runtime,omitempty\"`\n\t}","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/core/modules/config.go#L244-L280","documentation":"For non-legacy configs, UnmarshalJSON decodes the sdk object through a type alias so encoding/json's default behavior applies to the struct fields. If that unmarshal fails — wrong JSON types for fields, e.g. a string where an object is expected — the error is wrapped as \"unmarshal sdk as struct\" so the caller knows the modern (object-shaped) sdk decode is what failed.","triggerScenarios":"A dagger.json where sdk is an object (or any non-string value) whose inner fields have mismatched types, e.g. \"sdk\": \"python\" going through the struct path after the alias unmarshal rejects it, or \"sdk\": {\"source\": 123} with a non-string source.","commonSituations":"Hand-edited configs with wrong field types; mixing legacy and current config shapes after an upgrade; tooling that writes sdk with the wrong JSON types.","solutions":["Check the sdk field shape in dagger.json: current format is an object like {\"source\": \"python\"}, legacy is a string","Fix field types inside the sdk object to match SDK's JSON schema (string source, etc.)","Validate the config with `jq . dagger.json` and by running a dagger command that loads the module","Regenerate dagger.json with `dagger mod init` or `dagger mod sync` to get a canonical shape"],"exampleFix":"// dagger.json before\n\"sdk\": { \"source\": 123 }\n// after\n\"sdk\": { \"source\": \"python\" }","handlingStrategy":"validation","validationCode":"// check sdk is either a string (legacy) or an object with a string source\nvar probe struct {\n\tSDK json.RawMessage `json:\"sdk\"`\n}\njson.Unmarshal(raw, &probe)\nvar obj struct{ Source string `json:\"source\"` }\nif err := json.Unmarshal(probe.SDK, &obj); err != nil {\n\treturn fmt.Errorf(\"sdk must be a string or {\\\"source\\\": string}\")\n}","typeGuard":null,"tryCatchPattern":"var cfg modules.ModuleConfig\nif err := json.Unmarshal(raw, &cfg); err != nil {\n\treturn fmt.Errorf(\"invalid sdk object in dagger.json: %w\", err)\n}","preventionTips":["Keep the current shape: \"sdk\": {\"source\": \"python\"}","Never mix legacy string form with new object fields in one file","Regenerate the config with `dagger mod sync` after SDK upgrades"],"tags":["dagger","module-config","json-unmarshal","type-mismatch"],"backgroundTag":"json-unmarshal-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"}