conductor-oss/conductor · error · RuntimeException

Anthropic Messages API call failed: {message}

Error message

Anthropic Messages API call failed: {message}

What it means

AnthropicChatModel.call() wraps any java.io.IOException thrown by AnthropicMessagesApi.createMessage() into a RuntimeException with this message. The underlying IOException (connection timeout, read timeout, DNS failure, TLS error) is preserved as the cause. This is the catch-all for all transport-layer failures between Conductor and api.anthropic.com; HTTP error responses (non-2xx status codes) are handled separately inside createMessage itself (see error 182).

Source

Thrown at ai/src/main/java/org/conductoross/conductor/ai/providers/anthropic/AnthropicChatModel.java:72

public class AnthropicChatModel implements ChatModel {

    private static final int DEFAULT_MAX_TOKENS = 8192;

    private final AnthropicMessagesApi messagesApi;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public AnthropicChatModel(AnthropicMessagesApi messagesApi) {
        this.messagesApi = messagesApi;
    }

    @Override
    public ChatResponse call(Prompt prompt) {
        try {
            MessagesRequest request = buildRequest(prompt);
            MessagesResponse result = messagesApi.createMessage(request);
            return toSpringChatResponse(result, prompt.getOptions());
        } catch (IOException e) {
            throw new RuntimeException("Anthropic Messages API call failed: " + e.getMessage(), e);
        }
    }

    private MessagesRequest buildRequest(Prompt prompt) {
        List<org.springframework.ai.chat.messages.Message> springMessages =
                prompt.getInstructions();
        ChatOptions options = prompt.getOptions();

        // Extract system messages
        String system = null;
        List<org.springframework.ai.chat.messages.Message> nonSystemMessages = new ArrayList<>();
        for (org.springframework.ai.chat.messages.Message msg : springMessages) {
            if (msg.getMessageType() == MessageType.SYSTEM) {
                String sysText = ((SystemMessage) msg).getText();
                system = system == null ? sysText : system + "\n" + sysText;
            } else {
                nonSystemMessages.add(msg);
            }

View on GitHub (pinned to cf7c3e4a8a)

Solutions

  1. Inspect the cause (getCause()) and its message — it carries the specific I/O failure reason.
  2. Verify network connectivity to config.getBaseURL() (default https://api.anthropic.com) from the Conductor host.
  3. If the request is large (many tokens, multi-image), increase the OkHttp readTimeout via AIHttpClients configuration.
  4. If behind a proxy, set the appropriate OkHttp proxy configuration.

Example fix

// before — default client with short timeout
Anthropic anthropic = new Anthropic(config);

// after — custom client with longer timeout
OkHttpClient httpClient = new OkHttpClient.Builder()
    .connectTimeout(30, TimeUnit.SECONDS)
    .readTimeout(120, TimeUnit.SECONDS)
    .build();
Anthropic anthropic = new Anthropic(config, httpClient);
Defensive patterns

Strategy: retry

Validate before calling

// Validate Anthropic config before calling the chat model
void validateAnthropicConfig(AnthropicConfiguration config) {
    if (config.getApiKey() == null || config.getApiKey().isBlank()) {
        throw new IllegalArgumentException("Anthropic API key is required");
    }
    if (config.getBaseURL() == null || config.getBaseURL().isBlank()) {
        throw new IllegalArgumentException("Anthropic base URL is required");
    }
}

Try / catch

// Retry on transient IOException, fail fast on permanent errors
int maxRetries = 3;
for (int attempt = 0; attempt <= maxRetries; attempt++) {
    try {
        return chatModel.call(prompt);
    } catch (RuntimeException e) {
        if (e.getCause() instanceof java.io.IOException
                && attempt < maxRetries) {
            Thread.sleep((long) Math.pow(2, attempt) * 1000);
            continue;
        }
        throw e;
    }
}

Prevention

When it happens

Trigger: The OkHttp POST to {baseUrl}/v1/messages fails at the transport layer: socket timeout, connection refused, DNS resolution failure for api.anthropic.com, TLS handshake failure, or the OkHttp client's readTimeout is exceeded for a large streaming-adjacent request.

Common situations: OkHttp default timeout too short for large-context Claude requests. Corporate proxy or firewall blocking api.anthropic.com. Incorrect baseUrl configured in AnthropicConfiguration pointing to an unreachable host. Intermittent network partition or DNS blip in containerised deployments.

Related errors


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