dagger/dagger · error
unmarshal sdk as struct: %w
Error message
unmarshal sdk as struct: %w
What it means
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.
Source
Thrown at core/modules/config.go:262
if len(data) == 0 {
sdk.Source = ""
return nil
}
// check if this is a legacy config, where sdk was a string
if data[0] == '"' {
var sdkRefStr string
if err := json.Unmarshal(data, &sdkRefStr); err != nil {
return fmt.Errorf("unmarshal sdk as string: %w", err)
}
*sdk = SDK{Source: sdkRefStr}
return nil
}
type alias SDK // lets us use the default json unmashaler
var tmp alias
if err := json.Unmarshal(data, &tmp); err != nil {
return fmt.Errorf("unmarshal sdk as struct: %w", err)
}
*sdk = SDK(tmp)
return nil
}
func (modCfg *ModuleConfig) UnmarshalJSON(data []byte) error {
if modCfg == nil {
return fmt.Errorf("cannot unmarshal into nil %T", modCfg)
}
if len(data) == 0 {
return nil
}
type alias ModuleConfig // lets us use the default json unmashaler
var tmp struct {
alias
Runtime *SDK `json:"runtime,omitempty"`
}View on GitHub (pinned to 82ba2681db)
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
Example fix
// dagger.json before
"sdk": { "source": 123 }
// after
"sdk": { "source": "python" } Defensive patterns
Strategy: validation
Validate before calling
// check sdk is either a string (legacy) or an object with a string source
var probe struct {
SDK json.RawMessage `json:"sdk"`
}
json.Unmarshal(raw, &probe)
var obj struct{ Source string `json:"source"` }
if err := json.Unmarshal(probe.SDK, &obj); err != nil {
return fmt.Errorf("sdk must be a string or {\"source\": string}")
} Try / catch
var cfg modules.ModuleConfig
if err := json.Unmarshal(raw, &cfg); err != nil {
return fmt.Errorf("invalid sdk object in dagger.json: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- cannot unmarshal into nil SDK
- cannot unmarshal into nil %T
- unmarshal module config: %w
- failed to generate field type code: %w
- failed to generate set field code: %w
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/f292ed9bae31d2fb.
Report an issue: GitHub.