{"record":{"id":"b35f832ab59fd442","repo":"vxcontrol/pentagi","slug":"unexpected-status-code-d-b35f83","errorCode":null,"errorMessage":"unexpected status code: %d","messagePattern":"unexpected status code: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/searchers/traversaal.go","lineNumber":106,"sourceCode":"\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\treq.Header.Set(\"x-api-key\", t.apiKey())\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(resp)\n}\n\nfunc (t *traversaal) parseHTTPResponse(resp *http.Response) (string, error) {\n\tif resp.StatusCode != http.StatusOK {\n\t\terr := fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t\tif resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500 {\n\t\t\treturn \"\", Retryable(err, 0)\n\t\t}\n\t\treturn \"\", Fatal(err)\n\t}\n\tvar respBody struct {\n\t\tData traversaalSearchResult `json:\"data\"`\n\t}\n\tif err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {\n\t\treturn \"\", Fatal(fmt.Errorf(\"failed to decode response body: %v\", err))\n\t}\n\n\tvar writer strings.Builder\n\twriter.WriteString(\"# Answer\\n\\n\")\n\twriter.WriteString(respBody.Data.Response)\n\twriter.WriteString(\"\\n\\n# Links\\n\\n\")\n\n\tfor i, resultLink := range respBody.Data.Links {","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/searchers/traversaal.go#L88-L124","documentation":"traversaal.parseHTTPResponse rejects any non-200 status with 'unexpected status code: %d'. Statuses 429 or >=500 are wrapped as Retryable (transient server/load problems); everything else (400, 401, 403, 404...) is Fatal, meaning retrying the same engine will not help.","triggerScenarios":"search() receives any non-OK status from the Traversaal API and parseHTTPResponse builds fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode), then classifies: 429 or >=500 -> Retryable, otherwise Fatal.","commonSituations":"Invalid/missing Traversaal API key (401/403); malformed query rejected (400); rate limiting (429); Traversaal outage (5xx); endpoint path changed (404).","solutions":["Log and check the status code embedded in the message to pick the fix.","For 401/403: verify the Traversaal API key configuration (x-api-key header source).","For 400: inspect the query being sent; for 404: update traversaalURL to the current API endpoint.","For 429/5xx: let the Retryable classification drive retry/fallback to another engine."],"exampleFix":"// before: retrying all failures blindly\nresult, err := traversaal.Handle(ctx, req)\nif err != nil { result, err = traversaal.Handle(ctx, req) }\n// after: retry only Retryable, fail over otherwise\nif err != nil && !searchers.IsRetryable(err) {\n    return fallbackEngine.Handle(ctx, req)\n}","handlingStrategy":"type-guard","validationCode":"if os.Getenv(\"TRAVERSAAL_API_KEY\") == \"\" {\n    return errors.New(\"traversaal engine not configured; skipping\")\n}","typeGuard":"func classifySearcherError(err error) (retryable bool) {\n    var r *searchers.RetryableError\n    return errors.As(err, &r)\n}","tryCatchPattern":"result, err := traversaalSearcher.Handle(ctx, req)\nif err != nil {\n    if classifySearcherError(err) {\n        return retryWithBackoffOrFallback(req)\n    }\n    var f *searchers.FatalError\n    if errors.As(err, &f) && strings.Contains(f.Error(), \"401\") {\n        return \"\", fmt.Errorf(\"traversaal auth failed: check API key\")\n    }\n    return fallbackEngine.Handle(ctx, req)\n}","preventionTips":["Validate the API key at startup with an authenticated smoke request","Treat 429/5xx as retryable and everything else as engine switch","Monitor status-code frequency to catch API contract changes"],"tags":["http","traversaal","status-code","rate-limit","auth"],"backgroundTag":"unexpected-http-status-code","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}