vxcontrol/pentagi · error · Fatal
request is invalid
Error message
request is invalid
What it means
Thrown in tavily.parseHTTPResponse when the Tavily /search endpoint answers HTTP 400 Bad Request, mapped to the static message "request is invalid". Classified Fatal: the request body was rejected by the API as malformed or semantically invalid, so retrying the identical request will not help. The searcher deliberately discards Tavily's own error detail and returns this generic message.
Source
Thrown at backend/pkg/tools/searchers/tavily.go:150
resp, err := client.Do(req)
if err != nil {
return "", Retryable(fmt.Errorf("failed to do request: %v", err), 0)
}
defer resp.Body.Close()
return t.parseHTTPResponse(ctx, resp)
}
func (t *tavily) parseHTTPResponse(ctx context.Context, resp *http.Response) (string, error) {
switch resp.StatusCode {
case http.StatusOK:
var respBody tavilySearchResult
if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {
return "", Fatal(fmt.Errorf("failed to decode response body: %v", err))
}
return t.buildTavilyResult(ctx, &respBody), nil
case http.StatusBadRequest:
return "", Fatal(fmt.Errorf("request is invalid"))
case http.StatusUnauthorized:
return "", Fatal(fmt.Errorf("API key is wrong"))
case http.StatusForbidden:
return "", Fatal(fmt.Errorf("the endpoint requested is hidden for administrators only"))
case http.StatusNotFound:
return "", Fatal(fmt.Errorf("the specified endpoint could not be found"))
case http.StatusMethodNotAllowed:
return "", Fatal(fmt.Errorf("there need to try to access an endpoint with an invalid method"))
case http.StatusTooManyRequests:
return "", Retryable(fmt.Errorf("there are requesting too many results"), 0)
case http.StatusInternalServerError:
return "", Retryable(fmt.Errorf("there had a problem with our server. try again later"), 0)
case http.StatusBadGateway:
return "", Retryable(fmt.Errorf("there was a problem with the server. Please try again later"), 0)
case http.StatusServiceUnavailable:
return "", Retryable(fmt.Errorf("there are temporarily offline for maintenance. please try again later"), 0)
case http.StatusGatewayTimeout:
return "", Retryable(fmt.Errorf("there are temporarily offline for maintenance. please try again later"), 0)View on GitHub (pinned to ea665308ba)
Solutions
- Validate the Request before calling Tavily: reject empty/overlong queries and clamp MaxResults to the API's allowed range.
- Log the outgoing request body (query, max_results, search_depth) when this fires to identify which parameter the API rejected.
- Compare against the current Tavily /search API docs — parameter constraints may have changed.
- Capture Tavily's 400 response body (it contains a detail message) instead of the static string for faster diagnosis.
- If an agent generates the query, add prompt/schema-side guardrails so blank or malformed queries never reach the tool.
Example fix
// before
if strings.TrimSpace(req.Query) == "" { return "", ErrNotConfigured } // too late / wrong place
// after: guard in Handle before building the payload
q := strings.TrimSpace(req.Query)
if q == "" { return "", Fatal(fmt.Errorf("query must not be empty")) }
max := req.MaxResults
if max <= 0 { max = 5 } else if max > 20 { max = 20 } // keep within Tavily limits Defensive patterns
Strategy: validation
Validate before calling
q := strings.TrimSpace(req.Query)
if q == "" || len(q) > 400 {
return "", Fatal(fmt.Errorf("query must be 1-400 chars"))
}
max := req.MaxResults
if max <= 0 { max = 5 } else if max > 20 { max = 20 } Try / catch
if err != nil {
if errors.Is(err, ErrFatalSearcher) && strings.Contains(err.Error(), "request is invalid") {
// log the outgoing query/max_results, correct the input, do not blind-retry
}
return err
} Prevention
- Never pass agent-generated queries through unchecked — trim and bound them first.
- Keep MaxResults within Tavily's documented range.
- Diff your request parameters against the current Tavily API docs on upgrades.
- Include Tavily's 400 response body in logs rather than swallowing it with the static message.
When it happens
Trigger: POST to api.tavily.com/search returns 400: empty or whitespace-only query, max_results out of the API's allowed range, invalid search_depth/topic values, or a malformed JSON body.
Common situations: Agent calls web_search with an empty or garbage query that flows through unchanged to Tavily; max_results configured above Tavily's cap; a Tavily API update tightening parameter validation (e.g. search_depth allowed values) while the client still sends "advanced" defaults that become invalid on a plan tier.
Related errors
- failed to decode response body: %v
- ErrScreenshotsInvalidRequest
- ErrSearchlogsInvalidRequest
- ErrSubtasksInvalidRequest
- ErrTasksInvalidRequest
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/06fa6ba93d83781d.
Report an issue: GitHub.