{"record":{"id":"0e3d585a88f369d3","repo":"conductor-oss/conductor","slug":"anthropic-messages-api-call-failed-message","errorCode":null,"errorMessage":"Anthropic Messages API call failed: {message}","messagePattern":"Anthropic Messages API call failed: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"ai/src/main/java/org/conductoross/conductor/ai/providers/anthropic/AnthropicChatModel.java","lineNumber":72,"sourceCode":"public class AnthropicChatModel implements ChatModel {\n\n    private static final int DEFAULT_MAX_TOKENS = 8192;\n\n    private final AnthropicMessagesApi messagesApi;\n    private final ObjectMapper objectMapper = new ObjectMapper();\n\n    public AnthropicChatModel(AnthropicMessagesApi messagesApi) {\n        this.messagesApi = messagesApi;\n    }\n\n    @Override\n    public ChatResponse call(Prompt prompt) {\n        try {\n            MessagesRequest request = buildRequest(prompt);\n            MessagesResponse result = messagesApi.createMessage(request);\n            return toSpringChatResponse(result, prompt.getOptions());\n        } catch (IOException e) {\n            throw new RuntimeException(\"Anthropic Messages API call failed: \" + e.getMessage(), e);\n        }\n    }\n\n    private MessagesRequest buildRequest(Prompt prompt) {\n        List<org.springframework.ai.chat.messages.Message> springMessages =\n                prompt.getInstructions();\n        ChatOptions options = prompt.getOptions();\n\n        // Extract system messages\n        String system = null;\n        List<org.springframework.ai.chat.messages.Message> nonSystemMessages = new ArrayList<>();\n        for (org.springframework.ai.chat.messages.Message msg : springMessages) {\n            if (msg.getMessageType() == MessageType.SYSTEM) {\n                String sysText = ((SystemMessage) msg).getText();\n                system = system == null ? sysText : system + \"\\n\" + sysText;\n            } else {\n                nonSystemMessages.add(msg);\n            }","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/conductor-oss/conductor/blob/cf7c3e4a8adfb158be778ab1ec525323c363cd3a/ai/src/main/java/org/conductoross/conductor/ai/providers/anthropic/AnthropicChatModel.java#L54-L90","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Inspect the cause (getCause()) and its message — it carries the specific I/O failure reason.","Verify network connectivity to config.getBaseURL() (default https://api.anthropic.com) from the Conductor host.","If the request is large (many tokens, multi-image), increase the OkHttp readTimeout via AIHttpClients configuration.","If behind a proxy, set the appropriate OkHttp proxy configuration."],"exampleFix":"// before — default client with short timeout\nAnthropic anthropic = new Anthropic(config);\n\n// after — custom client with longer timeout\nOkHttpClient httpClient = new OkHttpClient.Builder()\n    .connectTimeout(30, TimeUnit.SECONDS)\n    .readTimeout(120, TimeUnit.SECONDS)\n    .build();\nAnthropic anthropic = new Anthropic(config, httpClient);","handlingStrategy":"retry","validationCode":"// Validate Anthropic config before calling the chat model\nvoid validateAnthropicConfig(AnthropicConfiguration config) {\n    if (config.getApiKey() == null || config.getApiKey().isBlank()) {\n        throw new IllegalArgumentException(\"Anthropic API key is required\");\n    }\n    if (config.getBaseURL() == null || config.getBaseURL().isBlank()) {\n        throw new IllegalArgumentException(\"Anthropic base URL is required\");\n    }\n}","typeGuard":null,"tryCatchPattern":"// Retry on transient IOException, fail fast on permanent errors\nint maxRetries = 3;\nfor (int attempt = 0; attempt <= maxRetries; attempt++) {\n    try {\n        return chatModel.call(prompt);\n    } catch (RuntimeException e) {\n        if (e.getCause() instanceof java.io.IOException\n                && attempt < maxRetries) {\n            Thread.sleep((long) Math.pow(2, attempt) * 1000);\n            continue;\n        }\n        throw e;\n    }\n}","preventionTips":["Configure OkHttp with generous connect/read timeouts (30s/120s) for Claude API calls via a custom OkHttpClient passed to the Anthropic constructor.","Verify network connectivity to api.anthropic.com from the Conductor host before deploying.","Log the cause exception (getCause()) to distinguish transport failures from API rejections.","Use exponential backoff retry for transient IOException causes."],"tags":["anthropic","network","io","timeout","chat"],"backgroundTag":null,"analyzedSha":"cf7c3e4a8adfb158be778ab1ec525323c363cd3a","analyzedAt":"2026-08-14T03:33:19.897Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}