vxcontrol/pentagi · error · FatalError
failed to marshal request body: %w
Error message
failed to marshal request body: %w
What it means
Before sending, `search` serializes the CompletionRequest payload with `json.Marshal`. Failure is wrapped as Fatal (backend/pkg/tools/searchers/perplexity.go:168). With a fully in-code struct this is nearly impossible at runtime — it only happens if the payload contains values json cannot encode, such as NaN/Inf floats or a channel/func field added to the struct.
Source
Thrown at backend/pkg/tools/searchers/perplexity.go:168
}
// Forming the request
reqPayload := CompletionRequest{
Messages: messages,
Model: p.model(),
SearchContextSize: p.contextSize(),
MaxTokens: p.maxTokens(),
Temperature: p.temperature(),
TopP: p.topP(),
ReturnImages: false,
ReturnRelatedQuestions: false,
Stream: false,
}
// Serializing the request
reqBody, err := json.Marshal(reqPayload)
if err != nil {
return "", Fatal(fmt.Errorf("failed to marshal request body: %w", err))
}
// Creating HTTP request
req, err := http.NewRequestWithContext(ctx, http.MethodPost, perplexityURL, bytes.NewBuffer(reqBody))
if err != nil {
return "", Fatal(fmt.Errorf("failed to create request: %w", err))
}
// Setting request headers
req.Header.Set("Authorization", "Bearer "+p.apiKey())
req.Header.Set("Content-Type", "application/json")
// Sending the request
resp, err := client.Do(req)
if err != nil {
return "", Retryable(fmt.Errorf("failed to send request: %w", err), 0)
}
defer resp.Body.Close()View on GitHub (pinned to ea665308ba)
Solutions
- Check the wrapped marshal error — it names the offending field/type
- Validate config-derived floats with math.IsNaN/IsInf before building reqPayload and fall back to defaults
- Revert recent changes to CompletionRequest; keep only JSON-serializable field types with correct tags
- Log reqPayload fields at debug level to spot the bad value
Example fix
// before
temp := parseTemperature(env) // NaN possible
// after
temp := parseTemperature(env)
if math.IsNaN(temp) || math.IsInf(temp, 0) {
temp = defaultTemperature
} Defensive patterns
Strategy: validation
Validate before calling
// validate numeric config before building the payload
for _, v := range []float64{temp, topP} {
if math.IsNaN(v) || math.IsInf(v, 0) {
return fmt.Errorf("non-finite value in Perplexity config")
}
} Try / catch
_, err := engine.Handle(ctx, req)
if err != nil && searchers.IsFatal(err) && strings.Contains(err.Error(), "failed to marshal request body") {
// inspect logged payload fields for NaN/Inf or non-serializable values
} Prevention
- Clamp/sanitize Temperature, TopP, MaxTokens parsed from env to sane finite ranges
- Keep CompletionRequest fields JSON-encodable with correct tags
- Add a debug log of the request payload before marshal in development
- Test config parsing edge cases in unit tests (config_test.go)
When it happens
Trigger: `json.Marshal(reqPayload)` errors because a field value is not JSON-encodable — e.g. a NaN/±Inf float leaking into Temperature/TopP from a misparsed config, or a custom build that added an unsupported field type to CompletionRequest.
Common situations: Temperature/TopP env var parsed via strconv/regex producing NaN; custom fork patched CompletionRequest with a non-serializable field; json tag/type mismatch after a struct refactor.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- knowledge: marshal cmetadata: %w
- failed to marshal provider config: %w
- failed to marshal request body: %v
- failed to marshal request body: %w
- failed to marshal request body: %v
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/9b9b1083523f84af.
Report an issue: GitHub.