{"record":{"id":"9f1e61ae1b8caa2e","repo":"bytebase/bytebase","slug":"failed-to-marshal-tool-call-input-s","errorCode":null,"errorMessage":"failed to marshal tool call input: %s","messagePattern":"failed to marshal tool call input: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/api/v1/ai_service.go","lineNumber":472,"sourceCode":"\n\tvar resp chatClaudeResponse\n\tif err := json.Unmarshal(body, &resp); err != nil {\n\t\treturn nil, errors.Errorf(\"failed to unmarshal Claude response: %s\", err)\n\t}\n\n\tresult := &v1pb.AIChatResponse{}\n\tif resp.Usage != nil {\n\t\tresult.Usage = newAIChatUsage(resp.Usage.InputTokens + resp.Usage.OutputTokens)\n\t}\n\tvar textContent string\n\tfor _, block := range resp.Content {\n\t\tswitch block.Type {\n\t\tcase \"text\":\n\t\t\ttextContent += block.Text\n\t\tcase \"tool_use\":\n\t\t\targs, err := json.Marshal(block.Input)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Errorf(\"failed to marshal tool call input: %s\", err)\n\t\t\t}\n\t\t\tresult.ToolCalls = append(result.ToolCalls, &v1pb.AIChatToolCall{\n\t\t\t\tId:        block.ID,\n\t\t\t\tName:      block.Name,\n\t\t\t\tArguments: string(args),\n\t\t\t})\n\t\tdefault:\n\t\t}\n\t}\n\tif textContent != \"\" {\n\t\tresult.Content = &textContent\n\t}\n\treturn result, nil\n}\n\n// Gemini chat types with tool-calling support.\n\ntype chatGeminiRequest struct {","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/bytebase/bytebase/blob/1870550677fe08f0d2a78c07acd27541464eb945/backend/api/v1/ai_service.go#L454-L490","documentation":"chatClaude wraps errors.New when json.Marshal fails on a tool_use content block's Input field. Input is decoded as `any`, so the only realistic failures are unsupported types produced by a custom json.Unmarshaler or a decoding quirk (e.g. map keys of non-string kind via json.Number usage) — extremely rare with standard encoding/json output.","triggerScenarios":"Occurs while converting a Claude 'tool_use' content block to v1pb.AIChatToolCall when json.Marshal(block.Input) returns an error, typically only if block.Input contains a type encoding/json cannot serialize (unsupported func/channel, cyclic data) — practically only reachable with unusual custom decoding.","commonSituations":"Rarely seen in practice; could surface when the Claude API changes how tool inputs are represented or when a fork adds a custom unmarshaller producing non-marshalable values.","solutions":["Inspect block.Input's Go type at the failure point; ensure it only contains JSON-representable values.","Avoid replacing map[string]any with non-JSON-marshalable key types during decoding.","Include the tool name in the error message to identify which tool call failed, then reproduce against that tool's schema.","If reproducible, capture and file the raw tool_use block against the provider SDK/API version in use."],"exampleFix":"// before\nargs, err := json.Marshal(block.Input)\nif err != nil {\n\treturn nil, errors.Errorf(\"failed to marshal tool call input: %s\", err)\n}\n// after: add tool context\nargs, err := json.Marshal(block.Input)\nif err != nil {\n\treturn nil, errors.Errorf(\"failed to marshal tool call input for tool %s (block %s): %s\", block.Name, block.ID, err)\n}","handlingStrategy":"type-guard","validationCode":"func marshalable(v any) error {\n\t_, err := json.Marshal(v)\n\treturn err\n}","typeGuard":"if block.Input == nil {\n\targs = []byte(\"{}\")\n} else if err := marshalable(block.Input); err != nil { /* skip or report */ }","tryCatchPattern":"if err := json.Marshal(block.Input); err != nil {\n\treturn nil, fmt.Errorf(\"tool %s input not serializable: %w\", block.Name, err)\n}","preventionTips":["Keep tool input decoding strictly via encoding/json into any/map[string]any.","Avoid custom unmarshallers that introduce non-JSON-marshalable types.","Include tool name/id in error context for quick isolation."],"tags":["json","ai-integration","tool-calls"],"backgroundTag":"json-marshal-failed","analyzedSha":"1870550677fe08f0d2a78c07acd27541464eb945","analyzedAt":"2026-09-06T21:16:13.665Z","contentChangedAt":"2026-09-06T21:16:13.665Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}