conductor-oss/conductor · error · IOException
Chat Completions API failed with status %d: %s
Error message
Chat Completions API failed with status %d: %s
What it means
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).
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIChatCompletionsApi.java:88
Request httpRequest =
new Request.Builder()
.url(baseUrl + completionsPath)
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.post(RequestBody.create(jsonBody, JSON))
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
ResponseBody body = response.body();
String responseBody = body != null ? body.string() : "";
if (!response.isSuccessful()) {
// Some models (e.g. o-series via compatible endpoints) reject temperature.
if (response.code() == 400
&& responseBody.contains("temperature")
&& request.temperature() != null) {
return createChatCompletion(request.withoutTemperature());
}
throw new IOException(
"Chat Completions API failed with status %d: %s"
.formatted(response.code(), responseBody));
}
log.debug("Chat Completions API response: {}", responseBody);
return objectMapper.readValue(responseBody, ChatCompletionResult.class);
}
}
// -- Request DTOs --
@JsonInclude(JsonInclude.Include.NON_NULL)
public record ChatCompletionRequest(
String model,
List<MessageItem> messages,
Double temperature,
@JsonProperty("top_p") Double topP,
@JsonProperty("max_tokens") Integer maxTokens,
List<String> stop,View on GitHub (pinned to cf7c3e4a8a)
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).
Example fix
// before: OpenAI key used against xAI new OpenAIChatCompletionsApi(client, openaiKey, "https://api.x.ai/v1") // after: xAI key new OpenAIChatCompletionsApi(client, xaiKey, "https://api.x.ai/v1")
Defensive patterns
Strategy: retry
Validate before calling
// Validate request before calling the API
ChatCompletionRequest request = /* ... */;
if (request.model() == null || request.model().isBlank()) {
throw new IllegalArgumentException("Model is required");
}
if (request.messages() == null || request.messages().isEmpty()) {
throw new IllegalArgumentException("At least one message is required");
}
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("API key is required");
} Type guard
null
Try / catch
int maxRetries = 3;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
return api.createChatCompletion(request);
} catch (IOException e) {
String msg = e.getMessage();
if (msg.contains("429") || msg.contains("500") || msg.contains("503")) {
if (attempt < maxRetries) {
long delay = (long) Math.pow(2, attempt) * 1000;
Thread.sleep(delay);
continue;
}
}
throw new RuntimeException("Chat Completions failed after retries", e);
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Chat Completions API call failed:
- OpenAI Responses API call failed:
- Embeddings API failed with status %d: %s
- Image Generation API failed with status %d: %s
- Responses API failed with status %d: %s
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/7e0a3df100694351.
Report an issue: GitHub.