{"record":{"id":"7e0a3df100694351","repo":"conductor-oss/conductor","slug":"chat-completions-api-failed-with-status-d-s","errorCode":null,"errorMessage":"Chat Completions API failed with status %d: %s","messagePattern":"Chat Completions API failed with status (.+?): (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIChatCompletionsApi.java","lineNumber":88,"sourceCode":"        Request httpRequest =\n                new Request.Builder()\n                        .url(baseUrl + completionsPath)\n                        .header(\"Authorization\", \"Bearer \" + apiKey)\n                        .header(\"Content-Type\", \"application/json\")\n                        .post(RequestBody.create(jsonBody, JSON))\n                        .build();\n\n        try (Response response = httpClient.newCall(httpRequest).execute()) {\n            ResponseBody body = response.body();\n            String responseBody = body != null ? body.string() : \"\";\n            if (!response.isSuccessful()) {\n                // Some models (e.g. o-series via compatible endpoints) reject temperature.\n                if (response.code() == 400\n                        && responseBody.contains(\"temperature\")\n                        && request.temperature() != null) {\n                    return createChatCompletion(request.withoutTemperature());\n                }\n                throw new IOException(\n                        \"Chat Completions API failed with status %d: %s\"\n                                .formatted(response.code(), responseBody));\n            }\n            log.debug(\"Chat Completions API response: {}\", responseBody);\n            return objectMapper.readValue(responseBody, ChatCompletionResult.class);\n        }\n    }\n\n    // -- Request DTOs --\n\n    @JsonInclude(JsonInclude.Include.NON_NULL)\n    public record ChatCompletionRequest(\n            String model,\n            List<MessageItem> messages,\n            Double temperature,\n            @JsonProperty(\"top_p\") Double topP,\n            @JsonProperty(\"max_tokens\") Integer maxTokens,\n            List<String> stop,","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIChatCompletionsApi.java#L70-L106","documentation":"OpenAIChatCompletionsApi.createChatCompletion() throws IOException with message \"Chat Completions API failed with status %d: %s\" when the HTTP response is not 2xx. The %d is the HTTP status code, %s is the raw response body. This is the low-level OkHttp client used by OpenAI-compatible providers (Perplexity, Grok/xAI, Together). Before throwing, it retries once without temperature if the error is a 400 mentioning 'temperature' (o-series quirk).","triggerScenarios":"POST {baseUrl}/chat/completions returns a non-2xx status. Common: 401 (invalid API key), 429 (rate limit), 404 (wrong baseURL or model), 400 (invalid parameters, unsupported model), 500/502/503 (server error), 529 (overloaded). The response body typically contains a JSON error object.","commonSituations":"Wrong API key for the compatible provider; baseURL missing /v1 suffix or pointing to wrong host; model name not offered by the provider; rate limit under load; provider outage (5xx); content filter rejection.","solutions":["Read the status code and response body from the IOException message — they are included directly.","For 401: verify the API key is correct for this provider (not an OpenAI key used against Perplexity/xAI).","For 429: implement exponential backoff and retry; check the provider's rate-limit tier.","For 404: verify baseURL and model name; ensure the path is /chat/completions (the default completionsPath).","For 400 mentioning temperature: the code already retries once without it — if it still fails, check other parameters (top_p, stop, max_tokens for the specific model)."],"exampleFix":"// before: OpenAI key used against xAI\nnew OpenAIChatCompletionsApi(client, openaiKey, \"https://api.x.ai/v1\")\n// after: xAI key\nnew OpenAIChatCompletionsApi(client, xaiKey, \"https://api.x.ai/v1\")","handlingStrategy":"retry","validationCode":"// Validate request before calling the API\nChatCompletionRequest request = /* ... */;\nif (request.model() == null || request.model().isBlank()) {\n    throw new IllegalArgumentException(\"Model is required\");\n}\nif (request.messages() == null || request.messages().isEmpty()) {\n    throw new IllegalArgumentException(\"At least one message is required\");\n}\nif (apiKey == null || apiKey.isBlank()) {\n    throw new IllegalArgumentException(\"API key is required\");\n}","typeGuard":"null","tryCatchPattern":"int maxRetries = 3;\nfor (int attempt = 0; attempt <= maxRetries; attempt++) {\n    try {\n        return api.createChatCompletion(request);\n    } catch (IOException e) {\n        String msg = e.getMessage();\n        if (msg.contains(\"429\") || msg.contains(\"500\") || msg.contains(\"503\")) {\n            if (attempt < maxRetries) {\n                long delay = (long) Math.pow(2, attempt) * 1000;\n                Thread.sleep(delay);\n                continue;\n            }\n        }\n        throw new RuntimeException(\"Chat Completions failed after retries\", e);\n    }\n}","preventionTips":["Verify the API key is correct for the specific compatible provider.","Verify the baseURL and completionsPath match the provider's API.","Verify the model name is offered by the provider.","Implement retry with exponential backoff for 429/5xx responses.","Log the HTTP status code and response body for diagnosis."],"tags":["openai-compatible","chat-completion","http-error","network","api-error","ai"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}