Last week I bumped the openai package version in one of my agent projects, ran the test suite, watched every test go green, and almost pushed straight to production. Good thing I didn't. Two weeks ago, the OpenAI Python SDK quietly replaced its entire HTTP layer: it no longer uses httpx, the library most of us have never had to think about. It now uses httpx2, a new fork maintained by the Pydantic team. And one of the changes is the kind that passes every unit test and then detonates in a Docker container at 2 AM.
Your API calls still work. Your response models still parse. Your timeouts still mean what they meant. The break is somewhere sneakier: certificate verification.
I spent my evening reading the official migration guide, the HTTPX2 project docs, and the Hacker News discussion where people who maintain real deployments picked the change apart. Here is the full picture and the pre-deploy checklist I now run before touching the SDK version in any of my own infrastructure.
First, what actually happened
Three things changed at once, and it helps to separate them.
-
The OpenAI SDK switched HTTP clients. The
openaipackage now installs and useshttpx2for both sync and async. It no longer installshttpxat all, so the old dependency is gone from your lockfile unless you declare it yourself. - HTTPX2 is Pydantic's fork of HTTPX. The original HTTPX project, created by Tom Christie under the encode organization, saw limited activity in recent months. The maintainer closed off issues and discussions in February, writing that he didn't want to continue hosting an environment with the community's gender skew. A community fork called HTTPXYZ appeared first, then Pydantic started its own fork under the HTTPX2 name, and the HTTPXYZ authors publicly endorsed HTTPX2 as the blessed continuation. If you have ever used FastAPI or Pydantic, you know Pydantic ships code a lot of production systems depend on.
-
The trust store changed, and this is the part that bites. HTTPX verified TLS certificates against the
certifiCA bundle that pip installed for you. HTTPX2 verifies against your operating system's trust store instead, and the SDK no longer installscertifi. Same code, same tests, completely different source of truth for "is this certificate real."
The HN thread's top comment says it in one line: "nb: operating system TLS trust store is used now (instead of certifi)." Another commenter called it immediately: "This could be a breaking change (for some corporate network environments)." They were right, and here is why.
Full disclosure: I run my own AI agent infrastructure on a VPS, all of it in Docker containers, and I use the OpenAI Python SDK daily for the agents that research and draft my articles. I have hit this exact class of failure before, the SSL-error-inside-a-minimal-container kind, which is why I recognized the blast radius the moment I read the guide. I have not yet migrated every one of my projects to the new SDK version, so treat this as an operator's checklist, not a battle-tested war story.
Why the certifi change will find you eventually
Here is the scenario that plays out in a thousand codebases over the next month.
You build a Python image FROM python:3.13-slim. The slim images ship with almost nothing in them, including a minimal set of CA certificates. Under the old SDK, it did not matter much: certifi brought its own bundle, and TLS just worked. Under the new SDK, your HTTPS call to api.openai.com goes looking for CA certificates in the OS trust store, finds nothing or finds an incomplete set, and you get a certificate verification error in an environment where the exact same code worked yesterday.
The three environments the migration guide calls out explicitly:
- Minimal container images without system CA certificates installed.
- Corporate networks with TLS-inspecting proxies, where your company's proxy presents its own certificates, and everyone solved this by pointing certifi at a custom bundle. That custom bundle is now ignored.
- Deployments that pinned or patched certifi for compliance or security reasons. Whatever you did to certifi, you now have to redo it at the OS level.
And here is the truly annoying part: this only breaks at the transport layer. Your mocked tests pass, because your test suite probably never establishes a real TLS connection. That is why I almost shipped it.
The 7-point pre-deploy checklist
I keep this in my deploy notes now. Run it before upgrading any service that uses the OpenAI SDK.
-
Point 1: Audit your imports for httpx. If your code imported
httpxonly because the SDK installed it transitively, that import is now broken. Either addhttpxas an explicit dependency or migrate those imports tohttpx2. Grep forimport httpxandfrom httpxacross your repo. Do not rely on your lockfile to tell you the truth, because the lockfile will happily keephttpxif something else pulls it in. -
Point 2: Check your base images for CA certificates. On Debian-based images, run
apt-get install -y ca-certificatesin your Dockerfile. Do this even if you think you don't need it. It costs you megabytes, not hours of 2 AM debugging. -
Point 3: If you used a custom certifi bundle, migrate it. The OS-level equivalent is the
SSL_CERT_FILEenvironment variable for a single bundle file, orSSL_CERT_DIRfor a directory of certificates:
export SSL_CERT_FILE=/etc/ssl/certs/corporate-ca-bundle.pem
export SSL_CERT_DIR=/etc/ssl/corporate-certs/
These are honored when trust_env=True, which is the default. This one environment variable is probably the highest-leverage fix in this entire article if you sit behind a corporate proxy.
-
Point 4: Update custom HTTP client construction. If you pass
http_client=to the SDK, swaphttpxobjects forhttpx2objects. The mapping is mechanical:httpx.Clientbecomeshttpx2.Client,httpx.Timeoutbecomeshttpx2.Timeout, same forURL,Limits,HTTPTransport,AsyncHTTPTransport, andMockTransport. The SDK ships helpers that preserve its recommended defaults:
from openai import OpenAI, DefaultHttpx2Client
client = OpenAI(
http_client=DefaultHttpx2Client(proxy="http://proxy.example.com:8080")
)
- Point 5: Pin your timeout types, not just values. Numeric timeouts are unchanged. But if you build granular timeouts anywhere, the object lives in a new module:
import httpx2
from openai import OpenAI
client = OpenAI(timeout=httpx2.Timeout(60.0, connect=5.0, read=20.0))
-
Point 6: Check your test mocks. This is the one that produces false confidence.
MockTransporthandlers must now accept and returnhttpx2.Requestandhttpx2.Responseobjects. And if your test suite uses RESPX to intercept HTTP calls, an RESPX version that only patches legacy HTTPX will silently not intercept the SDK's new default client. Your tests will make real network calls and you will not notice until the CI runner without internet access fails. Check your RESPX version before anything else. - Point 7: Know the escape hatch, and use it only as a bridge. If a hard dependency still requires legacy HTTPX, you can install it yourself and inject it:
from typing import Any, cast
import httpx
from openai import OpenAI
client = OpenAI(http_client=cast(Any, httpx.Client()))
Note the cast. Legacy clients fail static type checking now, which is the SDK team telling you, in type-checker language, that this path is temporary and may be removed. I would treat any code that lands here as carrying an expiration date.
What I would do differently if I were starting fresh
A few opinions from someone who maintains a handful of long-lived agent services and has been burned by dependency drift before.
-
Pin the SDK version in production services, upgrade deliberately. This migration shipped as a breaking change inside what looks like a routine package update. If your deploy pipeline does
pip install -U openaior uses a floating range inpyproject.toml, you adopted a new TLS trust model without deciding to. Pin exact versions and upgrade on your schedule, not the package index's. - Put one real HTTPS smoke test in your deployment checks. Every test suite I have written mocks the transport. That means none of them would have caught the trust store change. A single health-check call to the real API endpoint as a post-deploy step would have. It costs one API call. It would have saved a lot of people a bad morning.
- Treat the OS trust store as the single source of truth everywhere. Honestly, the certifi change is directionally correct. OS trust stores get patched by your package manager and your security team. A certifi bundle pinned in your lockfile does not. The pain is in the transition, not the destination.
-
If you maintain an internal SDK wrapper around OpenAI, update its type signatures now. If your wrapper accepts or returns
httpx.Request/httpx.Responseobjects, every downstream team using it inherits this migration. Doing thehttpx2swap once in the wrapper is the whole point of having a wrapper.
Why this story is bigger than one SDK
The part of the HN thread that stuck with me was not the migration details. It was the reminder of how much of the modern internet runs on a handful of HTTP libraries maintained by very few people. HTTPX is, or was, one of those. When its maintenance stalled and its maintainer closed the community down, Pydantic stepping in as steward was the best available outcome. But notice what the OpenAI SDK migration guide had to do: provide compatibility shims, an escape hatch, warnings that legacy support "may be discontinued." Even a clean fork under a well-funded maintainer means a migration tax paid by thousands of teams.
The lesson I take from it: for anything in your critical path, know who actually maintains the library, and what happens the day they stop. Your dependency tree is a set of informal agreements with strangers. Occasionally one of those agreements ends, and the invoice arrives as a production incident.
I write about AI infrastructure, backend engineering, and the unglamorous operational side of shipping AI systems every week. If that sounds useful, subscribe, it's free.
Now the question back to you: have you migrated anything to the new OpenAI SDK yet? Did the trust store change bite you, or did you get lucky? Tell me in the comments, especially if you are behind a corporate proxy, because that is the case I am least able to test myself.
Top comments (0)