{"record":{"id":"c5e79ea82e08d556","repo":"Billionmail/BillionMail","slug":"unexpected-api-response-d-s","errorCode":null,"errorMessage":"unexpected API response: %d %s","messagePattern":"unexpected API response: (.+?) (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/askai/supplier.go","lineNumber":547,"sourceCode":"\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer resp.Body.Close()\n\n\tswitch resp.StatusCode {\n\tcase http.StatusOK:\n\t\treturn nil // API key is successfully validated\n\tcase http.StatusUnauthorized:\n\t\treturn errors.New(\"invalid API key\")\n\tcase http.StatusNotFound:\n\t\treturn nil\n\tdefault:\n\t\treturn fmt.Errorf(\"unexpected API response: %d %s\",\n\t\t\tresp.StatusCode, http.StatusText(resp.StatusCode))\n\t}\n}\n\n// GetSupplierConfig retrieves the configuration for a specific supplier by its name.\n// It reads the configuration file and returns a Supplier struct containing the supplier's details.\n// If the configuration file does not exist or an error occurs, it returns an error.\nfunc GetSupplierConfig(supplierName string) (*Supplier, error) {\n\treturn ReadSupplierConfig(supplierName)\n}\n\n// SetSupplierStatus updates the status of a supplier in its configuration file.\n// It reads the existing configuration, modifies the status, and saves it back to the file.\nfunc SetSupplierStatus(supplierName string, status bool) error {\n\tsupplierConfig, err := ReadSupplierConfig(supplierName)\n\tif err != nil {\n\t\treturn errors.New(\"supplier configuration not found\")\n\t}","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/askai/supplier.go#L529-L565","documentation":"When the models endpoint responds with any status other than 200, 401, or 404, testAPIKeyValidity fails with 'unexpected API response: <code> <text>'. Notably, 404 is treated as success (some providers don't expose /models), so this error fires for statuses like 403, 429, 500, 502, 503.","triggerScenarios":"GET <baseUrl>/models returns 403 (forbidden), 429 (rate limited), 5xx (server error), or a gateway error while Testing runs.","commonSituations":"Provider outage or maintenance (5xx); key valid but lacking model-list permission (403); rate limiting during automated test loops (429); reverse proxy returning 502/503; endpoint behind an auth gateway with different error semantics.","solutions":["Read the status code in the message and act on it specifically (403 → permissions, 429 → backoff, 5xx → retry later)","Check the provider's status page for outages","Verify account permissions to access the models endpoint","Wait and retry with backoff if rate-limited","Confirm the baseUrl points to the correct API gateway, not a proxy that masks errors"],"exampleFix":"// before\nerr := askai.Testing(name, url, key) // hit 429 in a retry loop\n// after\nfor i := 0; i < 3; i++ {\n    err = askai.Testing(name, url, key)\n    if err == nil || !strings.Contains(err.Error(), \"429\") { break }\n    time.Sleep(time.Duration(1<<i) * time.Second)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var err error\nfor attempt := 0; attempt < 3; attempt++ {\n    err = askai.Testing(name, baseUrl, apiKey)\n    if err == nil || !strings.Contains(err.Error(), \"unexpected API response\") { break }\n    time.Sleep(time.Duration(1<<attempt) * time.Second)\n}\nif err != nil {\n    return fmt.Errorf(\"provider returned an unexpected status; check provider status page: %w\", err)\n}","preventionTips":["Check the provider status page before diagnosing as a local problem","Avoid tight test loops that trigger 429 rate limits","Verify account permissions if the message shows 403","Monitor gateway/proxy health if 5xx statuses recur"],"tags":["go","http","api","supplier","status-code"],"backgroundTag":"unexpected-http-status","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}