{"record":{"id":"fb82f8c8594b0aa3","repo":"crowdsecurity/crowdsec","slug":"unexpected-http-code-s","errorCode":null,"errorMessage":"unexpected http code : %s","messagePattern":"unexpected http code : (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/cticlient/client.go","lineNumber":74,"sourceCode":"\t\treturn nil, err\n\t}\n\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tif resp.StatusCode == http.StatusForbidden {\n\t\t\treturn nil, ErrUnauthorized\n\t\t}\n\n\t\tif resp.StatusCode == http.StatusTooManyRequests {\n\t\t\treturn nil, ErrLimit\n\t\t}\n\n\t\tif resp.StatusCode == http.StatusNotFound {\n\t\t\treturn nil, ErrNotFound\n\t\t}\n\n\t\treturn nil, fmt.Errorf(\"unexpected http code : %s\", resp.Status)\n\t}\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn respBody, nil\n}\n\nfunc (c *CrowdsecCTIClient) GetIPInfo(ip string) (*SmokeItem, error) {\n\tctx := context.TODO()\n\n\tbody, err := c.doRequest(ctx, http.MethodGet, smokeEndpoint+\"/\"+ip, nil)\n\tif err != nil {\n\t\tif errors.Is(err, ErrNotFound) {\n\t\t\treturn &SmokeItem{}, nil\n\t\t}","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/cticlient/client.go#L56-L92","documentation":"The CTI client's doRequest treats any HTTP status other than 200 OK and 404 Not Found as an error, returning fmt.Errorf(\"unexpected http code : %s\", resp.Status). Called by GetIPInfo, SearchIPs and Fire, this surfaces any non-2xx (other than the specially-handled 404) response from the remote API as a generic unexpected-status error.","triggerScenarios":"Calling GetIPInfo/SearchIPs/Fire when the remote endpoint answers with 401 (invalid API key), 403 (forbidden), 429 (rate limited), 5xx (server error), or any other status the client doesn't special-case.","commonSituations":"Expired or wrong CTT/CTI API key; exceeding the API quota (429); CAPI/CTI outage returning 502/503; proxy/firewall returning an HTML error page with a 403/502 status.","solutions":["Check resp.Status in the error to see the actual code returned by the server.","For 401/403: verify the API key configured for the CTI client is valid and active.","For 429: back off and retry later; the API quota is exhausted.","For 5xx: check the service's status page and retry; it is a server-side issue.","Verify network/proxy settings if an intermediary is intercepting requests."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// verify credentials before calling\nif apiKey == \"\" {\n    return fmt.Errorf(\"CTI API key not configured\")\n}","typeGuard":null,"tryCatchPattern":"item, err := client.GetIPInfo(ctx, ip)\nif err != nil {\n    var nf *cticlient.ErrNotFound\n    if errors.As(err, &nf) { /* unknown IP */ }\n    // otherwise inspect resp.Status: 401/403 -> fix key, 429 -> back off, 5xx -> retry later\n    log.Warnf(\"CTI request failed: %v\", err)\n}","preventionTips":["Keep the API key valid and rotated before expiry","Implement exponential backoff on 429","Monitor service status pages for 5xx outages","Route via a reliable network path (avoid intercepting proxies)"],"tags":["http","api","network"],"backgroundTag":"unexpected-http-status","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}