Python
Requests Library
SSLError
HTTPS
Troubleshooting

Python Requests throwing SSLError

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

An SSLError from Python requests means the HTTPS connection failed during certificate verification or TLS negotiation. The fix depends on the exact cause: an expired certificate, a self-signed certificate, a corporate proxy inserting its own certificate, an outdated CA bundle, or a hostname mismatch. The right debugging approach is to identify which of those cases you have before changing any code.

Typical Failure Shape

A simple request can fail like this:

python
1import requests
2
3try:
4    response = requests.get("https://example.com", timeout=10)
5    print(response.status_code)
6except requests.exceptions.SSLError as exc:
7    print("SSL failure:", exc)

The exception text often includes useful hints such as “certificate verify failed,” “hostname mismatch,” or “self signed certificate.”

Most Common Cause: Certificate Verification Failure

By default, requests verifies the server certificate against a trusted certificate authority bundle. That is the correct default. If the server certificate is invalid or the client does not trust the issuing CA, the handshake fails.

Common reasons:

  • self-signed certificate
  • expired certificate
  • wrong hostname in the certificate
  • missing corporate root CA
  • stale local CA bundle

The failure is not “Python being picky.” It is the client protecting you from an untrusted connection.

Update certifi First

If the target server is valid but your local trust store is stale, update the CA bundle that requests commonly uses.

bash
python -m pip install --upgrade certifi requests

You can inspect the CA file path:

python
import certifi
print(certifi.where())

This is a safe first step when the same endpoint works in a browser but fails in a Python environment with old dependencies.

Use a Custom CA Bundle When Required

In internal environments, TLS often depends on a private certificate authority. In that case, pass the CA bundle explicitly.

python
1import requests
2
3response = requests.get(
4    "https://internal.example.corp",
5    verify="/path/to/company-ca.pem",
6    timeout=10,
7)
8
9print(response.status_code)

This is the correct solution for corporate proxies and internal services that use organization-managed certificates.

Do Not Default to verify=False

You can disable verification:

python
1import requests
2
3response = requests.get(
4    "https://internal.example.corp",
5    verify=False,
6    timeout=10,
7)
8print(response.status_code)

But this should be a short-lived debugging step, not a production fix. Disabling verification removes the security guarantees HTTPS is supposed to provide.

If verify=False makes the request succeed, you have learned that the problem is trust configuration, not basic connectivity. That is useful diagnostically, but it is not the final answer.

Check Hostname Mismatch

TLS verification also checks that the hostname in the URL matches the certificate. If the certificate is for api.example.com but you connect to 10.0.0.5 or internal-host, the request can fail even though the certificate is otherwise valid.

Bad:

python
requests.get("https://10.0.0.5")

Better:

python
requests.get("https://api.example.com")

Use the DNS name that the certificate was issued for.

Corporate Proxy and MITM Cases

In many enterprise networks, outbound HTTPS passes through a proxy that resigns traffic with an internal CA. Browsers may trust that CA because it is installed system-wide, while your Python environment does not. That is why “it works in Chrome” and “it fails in requests” often happen together.

The fix is usually to install or reference the organization CA bundle, not to turn verification off.

Debugging Checklist

A practical order of operations is:

  1. print the full exception text
  2. confirm the URL hostname matches the certificate name
  3. update requests and certifi
  4. test with the correct corporate or internal CA bundle
  5. use verify=False only as a temporary diagnostic check

That sequence usually narrows the problem quickly without weakening security prematurely.

Timeouts and Retries Are Separate

Do not confuse SSL errors with ordinary connection or timeout failures. A TLS handshake failure is not solved by retry loops or larger timeouts. If the certificate path is wrong, every retry will fail the same way until trust configuration is fixed.

Common Pitfalls

The biggest mistake is suppressing certificate verification instead of fixing trust configuration. Another is connecting to an IP address when the certificate was issued for a hostname. Developers also often forget that corporate proxies change TLS behavior and require a custom CA. Finally, upgrading Python packages is sometimes enough, but not if the server certificate itself is actually invalid or expired.

Summary

  • 'requests raises SSLError when certificate verification or TLS negotiation fails.'
  • Start by reading the exact exception text and checking the URL hostname.
  • Update requests and certifi if the local CA bundle may be stale.
  • Use verify=/path/to/ca.pem for internal or corporate certificate authorities.
  • Treat verify=False as a temporary diagnostic tool, not a real fix.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.