{"record":{"id":"9a3851971c3bbe0c","repo":"vxcontrol/pentagi","slug":"failed-to-marshal-request-body-w-9a3851","errorCode":null,"errorMessage":"failed to marshal request body: %w","messagePattern":"failed to marshal request body: %w","errorType":"exception","errorClass":"Fatal","httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/searchers/sploitus.go","lineNumber":120,"sourceCode":"\t\treturn \"\", err\n\t}\n\n\treturn result, nil\n}\n\n// search calls the Sploitus API and returns a formatted markdown result string\nfunc (s *sploitus) search(ctx context.Context, query, exploitType, sort string, limit int) (string, error) {\n\treqBody := sploitusRequest{\n\t\tQuery:  query,\n\t\tType:   exploitType,\n\t\tSort:   sort,\n\t\tTitle:  false, // search only for titles\n\t\tOffset: 0,\n\t}\n\n\tbodyBytes, err := json.Marshal(reqBody)\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to marshal request body: %w\", err))\n\t}\n\n\tclient, err := system.GetHTTPClient(s.cfg)\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to create http client: %w\", err))\n\t}\n\n\tclient.Timeout = sploitusRequestTimeout\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, sploitusAPIURL, bytes.NewReader(bodyBytes))\n\tif err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to create request: %w\", err))\n\t}\n\n\t// Build referer with query to mimic browser behavior\n\treferer := fmt.Sprintf(\"https://sploitus.com/?query=%s\", url.QueryEscape(query))\n\n\t// Mimic Chrome browser headers to bypass Cloudflare protection","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/searchers/sploitus.go#L102-L138","documentation":"The Sploitus searcher wraps json.Marshal of the sploitusRequest struct; if marshaling fails the searcher returns a Fatal typed error that will not be retried. In practice a struct of plain fields cannot fail marshaling unless an unsupported type (e.g. channel, func, or a MarshalJSON method returning an error) is added to the request payload.","triggerScenarios":"Handle() on the Sploitus searcher builds reqBody and calls json.Marshal(reqBody); the error occurs when the request struct contains a value json cannot encode (unsupported type or a failing MarshalJSON implementation).","commonSituations":"A developer adds a field of type func, chan, sync.Mutex, or a custom type with a broken MarshalJSON method to sploitusRequest; it is almost never seen with the current struct of strings/ints/bools.","solutions":["Inspect the wrapped error to find the unsupported field type in sploitusRequest","Remove or convert the offending field to a JSON-encodable type (string, []string, int, bool)","Log the query/limit inputs passed from web_search.go to check no exotic value flows into the struct"],"exampleFix":"// before\nreqBody := sploitusRequest{Query: query, Callback: fn} // fn is func: not encodable\n// after\nreqBody := sploitusRequest{Query: query, Offset: 0}","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(reqBody); err != nil {\n    log.Fatalf(\"request 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":"if _, err := json.Marshal(reqBody); err != nil {\n    return \"\", Fatal(fmt.Errorf(\"failed to marshal request body: %w\", err))\n}","preventionTips":["Keep request structs limited to JSON-primitive types","Add a marshaling unit test for every request struct","Never embed funcs, channels, or sync primitives in API payloads"],"tags":["json","serialization","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"}