conductor-oss/conductor · error · IOException

Embeddings API failed with status %d: %s

Error message

Embeddings API failed with status %d: %s

What it means

OpenAIEmbeddingsApi.createEmbeddings() throws IOException with message "Embeddings 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}/embeddings. The auth header is configurable (Bearer token or api-key for Azure).

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/providers/openai/api/OpenAIEmbeddingsApi.java:75

        this(httpClient, apiKey, baseUrl, false);
    }

    public EmbeddingResult createEmbeddings(EmbeddingRequest request) throws IOException {
        String jsonBody = objectMapper.writeValueAsString(request);

        Request httpRequest =
                new Request.Builder()
                        .url(baseUrl + "/embeddings")
                        .header(authHeaderName, authHeaderValue)
                        .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()) {
                throw new IOException(
                        "Embeddings API failed with status %d: %s"
                                .formatted(response.code(), responseBody));
            }
            return objectMapper.readValue(responseBody, EmbeddingResult.class);
        }
    }

    @JsonInclude(JsonInclude.Include.NON_NULL)
    public record EmbeddingRequest(String model, String input, Integer dimensions) {}

    @JsonIgnoreProperties(ignoreUnknown = true)
    public record EmbeddingResult(String object, List<EmbeddingData> data, String model) {}

    @JsonIgnoreProperties(ignoreUnknown = true)
    public record EmbeddingData(String object, Integer index, List<Float> embedding) {}
}

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Read the status code and body from the IOException message.
  2. For 401: verify the API key is valid and not expired.
  3. For 429: implement batch processing with rate-limit-aware backoff; embeddings have per-minute token limits.
  4. For 400: check if the dimensions parameter is valid for the model (ada-002 doesn't support custom dimensions).
  5. For 400 input-too-long: chunk the input text before embedding.

Example fix

// before
new OpenAIEmbeddingsApi.EmbeddingRequest("text-embedding-ada-002", veryLongText, 256)
// after — ada-002 doesn't support custom dimensions
new OpenAIEmbeddingsApi.EmbeddingRequest("text-embedding-ada-002", veryLongText, null)
// or use a model that supports dimensions
new OpenAIEmbeddingsApi.EmbeddingRequest("text-embedding-3-small", veryLongText, 256)
Defensive patterns

Strategy: retry

Validate before calling

// Validate embedding request before calling
OpenAIEmbeddingsApi.EmbeddingRequest request = /* ... */;
if (request.model() == null || request.model().isBlank()) {
    throw new IllegalArgumentException("Embedding model is required");
}
if (request.input() == null || request.input().isBlank()) {
    throw new IllegalArgumentException("Input text is required");
}
// Validate dimensions is only set for models that support it
if (request.dimensions() != null && request.model().equals("text-embedding-ada-002")) {
    throw new IllegalArgumentException(
        "text-embedding-ada-002 does not support custom dimensions; use text-embedding-3-small/large");
}

Type guard

null

Try / catch

int maxRetries = 3;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
    try {
        return api.createEmbeddings(request);
    } catch (IOException e) {
        String msg = e.getMessage();
        if (msg.contains("429") && attempt < maxRetries) {
            long delay = (long) Math.pow(2, attempt) * 2000; // longer backoff for rate limits
            Thread.sleep(delay);
            continue;
        }
        throw e;
    }
}

Prevention

When it happens

Trigger: POST {baseUrl}/embeddings returns non-2xx. Common: 401 (invalid/expired API key), 429 (rate limit — embeddings are high-volume so this is frequent), 404 (wrong baseURL or model not found), 400 (invalid dimensions parameter for the model, input too long), 500 (server error).

Common situations: Expired API key; requesting dimensions on a model that doesn't support it (e.g. text-embedding-ada-002 ignores dimensions; text-embedding-3-small/large support it); input text exceeding the model's token limit; rate limit during bulk vector-store indexing; wrong baseURL.

Related errors


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/8403045f927b2e75. Report an issue: GitHub.