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

  1. Read the field name and expected type in the message and fix the JSON type in launch.json
  2. Wrap the value in quotes if a string is expected (program, mode, cwd, etc.)
  3. Use a number if a numeric field (e.g. port) is named
  4. 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

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


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/d631c934618a28c8. Report an issue: GitHub.