conductor-oss/conductor · error · IOException
Responses API failed with status %d: %s
Error message
Responses API failed with status %d: %s
What it means
OpenAIResponsesApi.createResponse() throws IOException with message "Responses 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 for POST {baseUrl}/responses (the newer OpenAI Responses API). Before throwing, it retries once without temperature if the error is a 400 mentioning 'temperature' (o-series models reject temperature). Auth header is configurable for Azure (api-key header) vs OpenAI (Bearer).
Source
Thrown at ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIResponsesApi.java:101
Request httpRequest =
new Request.Builder()
.url(baseUrl + "/responses")
.header(authHeaderName, authHeaderValue)
.header("Content-Type", "application/json")
.post(RequestBody.create(jsonBody, JSON))
.build();
try (Response response = httpClient.newCall(httpRequest).execute()) {
String responseBody = readBody(response);
if (!response.isSuccessful()) {
// o-series and some newer OpenAI models reject temperature — retry without it.
if (response.code() == 400
&& responseBody.contains("temperature")
&& request.temperature() != null) {
return createResponse(request.withoutTemperature());
}
throw new IOException(
"Responses API failed with status %d: %s"
.formatted(response.code(), responseBody));
}
log.debug("Responses API response: {}", responseBody);
return objectMapper.readValue(responseBody, ResponseResult.class);
}
}
private String readBody(Response response) throws IOException {
ResponseBody body = response.body();
return body != null ? body.string() : "";
}
// -- Request DTOs --
/**
* Reasoning config block on the Responses API request. OpenAI's Responses API takes a nested
* object {@code "reasoning": {"effort": "...", "summary": "..."}} rather than the flat {@codeView on GitHub (pinned to cf7c3e4a8a)
Solutions
- Read the status code and body from the IOException message.
- For 400 model-not-supported: switch to a Responses-API-compatible model (gpt-4o, gpt-4o-mini, o1, o3, o4-mini, gpt-5 series).
- For 401: verify the API key; if using Azure, ensure azureAuth=true so the api-key header is used instead of Bearer.
- For 429: implement backoff and retry.
- For 400 reasoning parameter issues: verify reasoningEffort/reasoningSummary values match what the model supports (only reasoning models accept these).
- Verify baseURL ends with /v1 (the OpenAI provider constructor normalizes this via ensureV1, but direct OpenAIResponsesApi construction does not).
Example fix
// before: Azure OpenAI using Bearer auth (wrong) new OpenAIResponsesApi(client, apiKey, "https://my-resource.openai.azure.com/v1", false) // after: use azureAuth=true for api-key header new OpenAIResponsesApi(client, apiKey, "https://my-resource.openai.azure.com/v1", true)
Defensive patterns
Strategy: retry
Validate before calling
// Validate response request before calling
OpenAIResponsesApi.ResponseRequest request = /* ... */;
if (request.model() == null || request.model().isBlank()) {
throw new IllegalArgumentException("Model is required");
}
if (apiKey == null || apiKey.isBlank()) {
throw new IllegalArgumentException("API key is required");
}
// Verify model is Responses-API-compatible
String model = request.model().toLowerCase();
boolean supportsResponses = model.startsWith("gpt-4o") || model.startsWith("o1")
|| model.startsWith("o3") || model.startsWith("o4") || model.startsWith("gpt-5");
if (!supportsResponses) {
log.warn("Model '{}' may not support the Responses API", request.model());
} Type guard
null
Try / catch
int maxRetries = 3;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
try {
return api.createResponse(request);
} catch (IOException e) {
String msg = e.getMessage();
// Retry transient errors
if ((msg.contains("429") || msg.contains("500") || msg.contains("503")
|| msg.contains("529")) && attempt < maxRetries) {
long delay = (long) Math.pow(2, attempt) * 1000;
Thread.sleep(delay);
continue;
}
throw e;
}
} Prevention
- Verify the model supports the Responses API (gpt-4o, o1, o3, o4, gpt-5 series).
- For Azure OpenAI, ensure azureAuth=true so the api-key header is used.
- Verify the baseURL ends with /v1 (the OpenAI provider normalizes this; direct API construction does not).
- Implement retry with exponential backoff for 429/5xx/529 responses.
- The code auto-retries without temperature for o-series 400s — don't manually remove temperature.
When it happens
Trigger: POST {baseUrl}/responses returns non-2xx. Common: 401 (invalid/expired API key), 429 (rate limit), 400 (model not supported by Responses API, invalid reasoning config, unsupported parameters), 404 (wrong baseURL or model), 500/502/503 (server error), 529 (overloaded).
Common situations: Using a model that only supports Chat Completions (not Responses API) like gpt-3.5-turbo; expired API key; rate limit; reasoning-model parameter conflicts (the code auto-retries without temperature but other params like topP/stop may conflict); Azure auth header misconfigured (using Bearer instead of api-key header); baseURL not ending in /v1.
Related errors
- OpenAI Responses API call failed:
- Embeddings API failed with status %d: %s
- Image Generation API failed with status %d: %s
- Embeddings API call failed:
- Speech API call failed:
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/ec6b16d73150099d.
Report an issue: GitHub.