{"record":{"id":"087d33125189741f","repo":"vxcontrol/pentagi","slug":"failed-to-marshal-request-body-v-087d33","errorCode":null,"errorMessage":"failed to marshal request body: %v","messagePattern":"failed to marshal request body: (.+?)","errorType":"exception","errorClass":"Fatal","httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/searchers/tavily.go","lineNumber":121,"sourceCode":"func (t *tavily) search(ctx context.Context, query string, maxResults int) (string, error) {\n\tclient, err := system.GetHTTPClient(t.cfg)\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to create http client: %w\", err))\n\t}\n\n\treqPayload := tavilyRequest{\n\t\tQuery:             query,\n\t\tApiKey:            t.apiKey(),\n\t\tTopic:             \"general\",\n\t\tSearchDepth:       \"advanced\",\n\t\tIncludeImages:     false,\n\t\tIncludeAnswer:     true,\n\t\tIncludeRawContent: true,\n\t\tMaxResults:        maxResults,\n\t}\n\treqBody, err := json.Marshal(reqPayload)\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to marshal request body: %v\", err))\n\t}\n\n\treq, err := http.NewRequest(http.MethodPost, tavilyURL, bytes.NewBuffer(reqBody))\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to build request: %v\", err))\n\t}\n\n\treq = req.WithContext(ctx)\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn \"\", Retryable(fmt.Errorf(\"failed to do request: %v\", err), 0)\n\t}\n\tdefer resp.Body.Close()\n\n\treturn t.parseHTTPResponse(ctx, resp)\n}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/searchers/tavily.go#L103-L139","documentation":"json.Marshal of the tavilyRequest struct failed inside tavily.search(); the searcher returns a Fatal error. With the current struct (strings/ints/bools) this cannot occur naturally — it appears only when a non-encodable field or failing MarshalJSON method is introduced.","triggerScenarios":"search() marshals reqPayload (Query, ApiKey, Topic, IncludeAnswer, IncludeRawContent, MaxResults); fails if a new field of unsupported type (chan, func, complex) or a broken MarshalJSON is added to tavilyRequest.","commonSituations":"A developer adds a custom field type or time.Time-like wrapper with an erroring MarshalJSON to tavilyRequest; caught immediately on first search.","solutions":["Inspect the wrapped error for the unsupported type name and locate that field in tavilyRequest","Convert the field to a JSON-encodable type or implement a correct MarshalJSON","Run a unit test marshaling a fully populated tavilyRequest to catch this before runtime"],"exampleFix":"// before\nPayload tavilyRequest{..., Callback: make(chan int)} // unsupported\n// after\nPayload tavilyRequest{..., MaxResults: maxResults}","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(reqPayload); err != nil {\n    log.Fatalf(\"tavily payload not encodable: %v\", err)\n}","typeGuard":"func isJSONEncodable(v any) bool { var b bytes.Buffer; enc := json.NewEncoder(&b); return enc.Encode(v) == nil }","tryCatchPattern":"reqBody, err := json.Marshal(reqPayload)\nif err != nil {\n    return \"\", Fatal(fmt.Errorf(\"failed to marshal request body: %v\", err))\n}","preventionTips":["Use %w instead of %v so errors.As/Is unwrapping works","Unit-test marshaling of tavilyRequest with all fields populated","Restrict payload structs to JSON-primitive field types"],"tags":["json","serialization","tavily","go"],"backgroundTag":"json-marshal-unsupported-type","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}