go-delve/delve · error
cannot unmarshal %v into %q of type %v
Error message
cannot unmarshal %v into %q of type %v
What it means
A launch/attach argument field was given a JSON value of the wrong Go type. Delve intercepts encoding/json's UnmarshalTypeError and rewrites it into a friendlier message naming the JSON value, the field, and the expected type (with substitutePath specially rewritten to {"from":string,"to":string}).
Source
Thrown at service/dap/types.go:305
LaunchAttachCommonConfig
}
// unmarshalLaunchAttachArgs wraps unmarshaling of launch/attach request's
// arguments attribute. Upon unmarshal failure, it returns an error massaged
// to be suitable for end-users.
func unmarshalLaunchAttachArgs(input json.RawMessage, config any) error {
if err := json.Unmarshal(input, config); err != nil {
if uerr, ok := err.(*json.UnmarshalTypeError); ok {
// Format json.UnmarshalTypeError error string in our own way. E.g.,
// "json: cannot unmarshal number into Go struct field LaunchArgs.substitutePath of type dap.SubstitutePath"
// => "cannot unmarshal number into 'substitutePath' of type {from:string, to:string}"
// "json: cannot unmarshal number into Go struct field LaunchArgs.program of type string" (go1.16)
// => "cannot unmarshal number into 'program' of type string"
typ := uerr.Type.String()
if uerr.Field == "substitutePath" {
typ = `{"from":string, "to":string}`
}
return fmt.Errorf("cannot unmarshal %v into %q of type %v", uerr.Value, uerr.Field, typ)
}
return err
}
return nil
}
func prettyPrint(config any) string {
pretty, err := json.MarshalIndent(config, "", "\t")
if err != nil {
return fmt.Sprintf("%#v", config)
}
return string(pretty)
}
// BuildFlags is either string or []string.
type BuildFlags struct {
value any
}View on GitHub (pinned to a23773e6c3)
Solutions
- Read the field name and expected type in the message and fix the JSON type in launch.json
- Wrap the value in quotes if a string is expected (program, mode, cwd, etc.)
- Use a number if a numeric field (e.g. port) is named
- Run your launch.json through schema validation before starting a debug session
Example fix
// before
{"request":"launch","mode":"debug","program":12345}
// after
{"request":"launch","mode":"debug","program":"/path/to/cmd"} Defensive patterns
Strategy: validation
Validate before calling
func checkLaunchArgTypes(cfg map[string]any) error {
strFields := []string{"program","mode","cwd","backend"}
for _, f := range strFields { if v, ok := cfg[f]; ok && v != nil { if _, ok := v.(string); !ok { return fmt.Errorf("field %q must be a string", f) } } }
return nil
} Type guard
func expectString(v any) (string, bool) { s, ok := v.(string); return s, ok } Try / catch
if err := startSession(args); err != nil { if strings.Contains(err.Error(), "cannot unmarshal") { /* parse field/type from message and fix launch.json */ } return err } Prevention
- Validate launch.json against the DAP delve schema
- Quote all string-typed fields; check numeric fields are numbers
- Copy configs between editors carefully — type conventions differ
When it happens
Trigger: onLaunchRequest or onAttachRequest where any field of LaunchArgs has a mismatched type, e.g. "program": 42, "port": "2345" vs number, or "mode": 1.
Common situations: Hand-edited launch.json with wrong-typed values, numeric program names, buildFlags given a wrong type handled separately, copy-paste between client configs.
Related errors
- cannot unmarshal %v into "buildFlags" of type []string or st
- cannot use %s as 'substitutePath' of type {"from":string, "t
- variable to reslice is not an array, slice, or map
- count/len must be a positive integer
- expected argument after -size
AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31).
Data as JSON: /api/errors/d631c934618a28c8.
Report an issue: GitHub.