SSL handshake failure to Anthropic Claude API after TLS cert rotation

Problem – SSL/TLS Handshake Failure When Calling Anthropic Claude API

Our cloud‑managed service attempts to invoke the Anthropic Claude API over HTTPS. After a scheduled TLS certificate rotation on the Anthropic side, all outbound requests started failing with a handshake error. The failure manifested as immediate connection aborts, no data returned, and a surge in error metrics.

Observed Symptoms

  • Python requests calls raise SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed.
  • cURL returns curl: (60) SSL certificate problem: unable to get local issuer certificate.
  • Application logs show repeated entries similar to:
2026-10-15 03:12:41,872 ERROR [api-client] SSL handshake failed for https://api.anthropic.com/v1/complete: 
    SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: 
    unable to get local issuer certificate (_ssl.c:1129)'))

Impact

  • All user‑facing features that rely on Claude completions become unavailable.
  • Error rate spikes from <1% to >95% in api_error_rate metric.
  • SLAs breached for downstream services.

Root Cause – Mismatch Between Updated Anthropic CA Chain and Stale Trust Store

Anthropic rotated the leaf certificate for api.anthropic.com and introduced a new intermediate CA signed by a recently added root that is not present in the default certifi bundle used by our runtime environment. The TLS handshake proceeds until the server presents its certificate chain. The client then attempts to build a trust path using the locally trusted roots. Because the new root is missing, the verification step fails, causing the handshake to abort.

Compounding the issue, the service runs on a hardened container image that disables the system ca-certificates package in favor of a pinned certifi version (2023.5.7). The rotation occurred after the image build, so the container never received the updated root CA.

Debug – Step‑by‑Step Investigation

  1. Confirm the failure with low‑level TLS diagnostics.
  2. openssl s_client -connect api.anthropic.com:443 -servername api.anthropic.com -showcerts

    Sample output (truncated):

    ...
    Certificate chain
     0 s:/CN=api.anthropic.com
       i:/C=US/O=NewRootCA/OU=Infrastructure/CN=NewRootCA Intermediate
     1 s:/C=US/O=NewRootCA/OU=Infrastructure/CN=NewRootCA Intermediate
       i:/C=US/O=NewRootCA/OU=Infrastructure/CN=NewRootCA Root
    ...
    Verify return code: 21 (unable to verify the first certificate)
  3. Check the client trust store.
  4. # Python REPL
    >>> import certifi, ssl
    >>> ssl.create_default_context(cafile=certifi.where()).get_ca_certs()
    # Output shows no entry for "NewRootCA Root"
  5. Inspect the container image.
  6. docker run --rm myservice:latest cat /etc/ssl/certs/ca-certificates.crt | grep -i "NewRootCA"

    No matches – the root is absent.

  7. Validate that the issue is isolated to the Anthropic endpoint.
  8. curl -v https://www.google.com
    # TLS handshake succeeds
  9. Review recent change logs.
  10. 2026-10-10 02:00:00 INFO  Cert rotation on Anthropic side – new intermediate and root CAs deployed.

Solution – Update Trust Store to Include New Anthropic Root CA

Two viable approaches were evaluated:

Approach Pros Cons
Update certifi dependency to a version that bundles the new root (2024.8.30). Minimal code change; respects existing pinning strategy. Requires redeploy of all services.
Mount an updated ca-certificates.crt file into the container and configure the HTTP client to use it. Can be rolled out via config change; does not affect other dependencies. Introduces a second source of truth for CAs.

Implementation – Updating certifi

We chose the first approach to keep a single source of trust anchors.

# requirements.txt (before)
certifi==2023.5.7
requests==2.31.0

# requirements.txt (after)
certifi==2024.8.30
requests==2.31.0

Rebuild and redeploy the container image:

docker build -t myservice:2026.10.15 .
docker push myservice:2026.10.15
kubectl set image deployment/myservice myservice=myrepo/myservice:2026.10.15 --record

Alternative – Mounting Updated CA Bundle

# Create a custom CA bundle on the host
cat /etc/ssl/certs/ca-certificates.crt new_root_ca.pem > /opt/custom-ca/ca-bundle.crt

# Kubernetes pod spec snippet
volumeMounts:
- name: custom-ca
  mountPath: /etc/ssl/certs/custom-ca.crt
  subPath: ca-bundle.crt
env:
- name: REQUESTS_CA_BUNDLE
  value: /etc/ssl/certs/custom-ca.crt
volumes:
- name: custom-ca
  configMap:
    name: custom-ca-configmap

Verify – Confirm Handshake Success and Functional Operation

  1. Run the same openssl s_client command. The verify return code should be 0 (ok).
  2. Execute a test request from the service container:
  3. python - <<'PY'
    import requests, json
    resp = requests.post(
        "https://api.anthropic.com/v1/complete",
        json={"model":"claude-2.0","prompt":"Hello"},
        timeout=5
    )
    print(resp.status_code, resp.json())
    PY
    

    Expected output:

    200 {'completion': 'Hello! How can I assist you today?'}
    
  4. Check monitoring dashboards – api_error_rate should drop back to baseline (<1%).
  5. Review logs for absence of SSL handshake failed entries.

Prevent – Operational Guardrails for Future Certificate Rotations

  • Automated CA bundle refresh. Add a CI step that runs pip install -U certifi and fails the build if a newer version is available.
  • Health check for TLS validation. Deploy a periodic job that performs an openssl s_client check against critical third‑party endpoints and raises an alert on non‑zero verify codes.
  • Version pinning policy. Pin certifi to a major version but allow minor updates via a weekly dependency bot (e.g., Dependabot) to capture new root CAs.
  • Runtime fallback. Configure HTTP clients to respect REQUESTS_CA_BUNDLE environment variable, enabling quick overrides without rebuilding images.
  • Change‑notification subscription. Subscribe to Anthropic’s security mailing list for advance notice of certificate rotations.

Related Topic Hub: LLM Systems Troubleshooting Hub

FAQ

  1. Why does the handshake succeed with curl but fail in Python?

    cURL on the host uses the system ca-certificates bundle, which was updated automatically. The Python runtime is locked to an older certifi bundle that lacks the new root, leading to verification failure.

  2. Can I disable certificate verification as a quick fix?

    Disabling verification (verify=False) bypasses TLS security and is not acceptable in production. It also masks the underlying trust issue and may cause downstream compliance failures.

  3. Do I need to update the OpenSSL version?

    No. The OpenSSL library in the container supports TLS 1.2/1.3. The failure is purely due to missing trust anchors, not protocol incompatibility.

  4. How do I know which CA is missing without contacting Anthropic?

    Run openssl s_client -showcerts and compare the presented chain against the local bundle. The first certificate that cannot be matched is the missing root.

  5. Will this issue reappear if Anthropic rotates intermediate certificates again?

    Only if the new intermediate is signed by a root not present in the client bundle. Keeping the CA bundle up‑to‑date mitigates recurrence.