{"record":{"id":"08f829ebf3985ebb","repo":"vxcontrol/pentagi","slug":"there-need-to-try-to-access-an-endpoint-with-an-in-08f829","errorCode":null,"errorMessage":"there need to try to access an endpoint with an invalid method","messagePattern":"there need to try to access an endpoint with an invalid method","errorType":"http","errorClass":"Fatal","httpStatus":405,"severity":"error","filePath":"backend/pkg/tools/searchers/tavily.go","lineNumber":158,"sourceCode":"\nfunc (t *tavily) parseHTTPResponse(ctx context.Context, resp *http.Response) (string, error) {\n\tswitch resp.StatusCode {\n\tcase http.StatusOK:\n\t\tvar respBody tavilySearchResult\n\t\tif err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil {\n\t\t\treturn \"\", Fatal(fmt.Errorf(\"failed to decode response body: %v\", err))\n\t\t}\n\t\treturn t.buildTavilyResult(ctx, &respBody), nil\n\tcase http.StatusBadRequest:\n\t\treturn \"\", Fatal(fmt.Errorf(\"request is invalid\"))\n\tcase http.StatusUnauthorized:\n\t\treturn \"\", Fatal(fmt.Errorf(\"API key is wrong\"))\n\tcase http.StatusForbidden:\n\t\treturn \"\", Fatal(fmt.Errorf(\"the endpoint requested is hidden for administrators only\"))\n\tcase http.StatusNotFound:\n\t\treturn \"\", Fatal(fmt.Errorf(\"the specified endpoint could not be found\"))\n\tcase http.StatusMethodNotAllowed:\n\t\treturn \"\", Fatal(fmt.Errorf(\"there need to try to access an endpoint with an invalid method\"))\n\tcase http.StatusTooManyRequests:\n\t\treturn \"\", Retryable(fmt.Errorf(\"there are requesting too many results\"), 0)\n\tcase http.StatusInternalServerError:\n\t\treturn \"\", Retryable(fmt.Errorf(\"there had a problem with our server. try again later\"), 0)\n\tcase http.StatusBadGateway:\n\t\treturn \"\", Retryable(fmt.Errorf(\"there was a problem with the server. Please try again later\"), 0)\n\tcase http.StatusServiceUnavailable:\n\t\treturn \"\", Retryable(fmt.Errorf(\"there are temporarily offline for maintenance. please try again later\"), 0)\n\tcase http.StatusGatewayTimeout:\n\t\treturn \"\", Retryable(fmt.Errorf(\"there are temporarily offline for maintenance. please try again later\"), 0)\n\tdefault:\n\t\treturn \"\", Fatal(fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode))\n\t}\n}\n\nfunc (t *tavily) buildTavilyResult(ctx context.Context, result *tavilySearchResult) string {\n\tvar writer strings.Builder\n\twriter.WriteString(\"# Answer\\n\\n\")","sourceCodeStart":140,"sourceCodeEnd":176,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/searchers/tavily.go#L140-L176","documentation":"Thrown in tavily.parseHTTPResponse when Tavily answers HTTP 405 Method Not Allowed, mapped to \"there need to try to access an endpoint with an invalid method\". The route exists but rejected POST — meaning the request reached something that does not accept POST on /search. Classified Fatal, since the method is fixed in code and retrying cannot change the outcome.","triggerScenarios":"search() issues http.MethodPost to the endpoint and receives 405: an intercepting proxy/API gateway only allows GET on that path, a misconfigured base URL points to a different service, or Tavily changes the endpoint's accepted method.","commonSituations":"Captive proxies or security appliances that block POST bodies and rewrite requests; a self-hosted Tavily-compatible mock that implements only GET; pasting the endpoint into an API gateway that maps only GET routes; caching middlewares stripping the method semantics.","solutions":["Test with curl -X POST https://api.tavily.com/search -H 'Content-Type: application/json' -d '{...}' to confirm whether POST is blocked in your network path.","Inspect proxy/security appliance rules that may rewrite or restrict POST to api.tavily.com and allow-list the host.","Verify the target URL has not been overridden to a gateway/mock lacking the POST route.","Check Tavily API docs for method changes and update search() if POST is no longer correct.","If a mock/self-hosted server is used in dev, add the POST /search handler to it."],"exampleFix":"// before: mock server only handles GET\nmux.HandleFunc(\"/search\", getOnlyHandler)\n// after: register POST (and method check)\nmux.HandleFunc(\"/search\", func(w http.ResponseWriter, r *http.Request) {\n    if r.Method != http.MethodPost { w.WriteHeader(http.StatusMethodNotAllowed); return }\n    searchHandler(w, r)\n})","handlingStrategy":"validation","validationCode":"// confirm POST is accepted before relying on the engine\nreq, _ := http.NewRequest(http.MethodOptions, \"https://api.tavily.com/search\", nil)\nresp, err := http.DefaultClient.Do(req)\nif err == nil {\n    allow := resp.Header.Get(\"Allow\")\n    if allow != \"\" && !strings.Contains(allow, http.MethodPost) {\n        return fmt.Errorf(\"POST not allowed on /search (Allow: %s)\", allow)\n    }\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"invalid method\") {\n        // inspect proxy/gateway method filters; switch engine meanwhile\n        return fallbackSearcher.Handle(ctx, req)\n    }\n    return err\n}","preventionTips":["Allow-list api.tavily.com including POST bodies in proxy/security appliance rules.","Keep dev mocks method-faithful: implement POST /search, not GET.","Check gateway route configs when fronting external APIs.","Validate with curl -X POST from the deployment environment during setup."],"tags":["http-405","http-method","searchers","proxy","go"],"backgroundTag":"http-405-method-not-allowed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}