{"record":{"id":"e2a02f005b391d94","repo":"github/copilot-sdk","slug":"failed-to-unmarshal-arguments-into-t-w","errorCode":null,"errorMessage":"failed to unmarshal arguments into %T: %w","messagePattern":"failed to unmarshal arguments into %T: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/definetool.go","lineNumber":56,"sourceCode":"\t\tParameters:  schema,\n\t\tHandler:     createTypedHandler(handler),\n\t}\n}\n\n// createTypedHandler wraps a typed handler function into the standard ToolHandler signature.\nfunc createTypedHandler[T any, U any](handler func(T, ToolInvocation) (U, error)) ToolHandler {\n\treturn func(inv ToolInvocation) (ToolResult, error) {\n\t\tvar params T\n\n\t\t// Convert arguments to typed struct via JSON round-trip\n\t\t// Arguments is already map[string]any from JSON-RPC parsing\n\t\tjsonBytes, err := json.Marshal(inv.Arguments)\n\t\tif err != nil {\n\t\t\treturn ToolResult{}, fmt.Errorf(\"failed to marshal arguments: %w\", err)\n\t\t}\n\n\t\tif err := json.Unmarshal(jsonBytes, &params); err != nil {\n\t\t\treturn ToolResult{}, fmt.Errorf(\"failed to unmarshal arguments into %T: %w\", params, err)\n\t\t}\n\n\t\tresult, err := handler(params, inv)\n\t\tif err != nil {\n\t\t\treturn ToolResult{}, err\n\t\t}\n\n\t\treturn normalizeResult(result)\n\t}\n}\n\n// normalizeResult converts any value to a ToolResult.\n// Strings pass through directly, ToolResult passes through, and other types\n// are JSON-serialized.\nfunc normalizeResult(result any) (ToolResult, error) {\n\tif result == nil {\n\t\treturn ToolResult{\n\t\t\tTextResultForLLM: \"\",","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/definetool.go#L38-L74","documentation":"After marshaling, the arguments are unmarshaled into the tool's typed parameter struct T. If the arguments do not match the struct's field types/requirements, json.Unmarshal fails and the error is wrapped with this message including the target type. It means the caller supplied arguments that don't fit the tool's declared parameter schema.","triggerScenarios":"Calling a tool with a missing required field, wrong JSON type (string where number expected), or a value failing a custom UnmarshalJSON — anything that makes the round-trip into T fail.","commonSituations":"LLM or client sending malformed tool arguments; API surface changed (renamed/retyped field) while callers send the old shape; numbers sent as strings; nested objects not matching struct tags.","solutions":["Read the wrapped unmarshal error: it names the offending field and expected type","Compare the sent arguments against the tool's input schema and correct types/field names","Ensure required fields are present and JSON types match the Go struct (e.g. no stringified numbers)","If the schema changed, update clients to the new argument shape"],"exampleFix":"// before\n{\"count\": \"3\"}        // string where int expected\n// after\n{\"count\": 3}          // correct JSON type for params.Count int","handlingStrategy":"validation","validationCode":"// validate arguments against the tool schema before invoking\njsonBytes, _ := json.Marshal(args)\nvar probe MyToolParams\nif err := json.Unmarshal(jsonBytes, &probe); err != nil { /* reject early */ }","typeGuard":null,"tryCatchPattern":"// Go\nres, err := tool.Invoke(inv)\nvar typeErr *json.UnmarshalTypeError\nif err != nil && errors.As(err, &typeErr) {\n\t// typeErr.Field names the mismatched argument field\n}","preventionTips":["Publish and follow each tool's input schema","Send correct JSON types (numbers as numbers, not strings)","Update client argument shapes when tool schemas change"],"tags":["json","mcp","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}