TLDR: macOS system Python has no CA cert bundle. curl does. Route your one-off fetch scripts through a curl subprocess — two lines, no dependencies, problem gone.

The Setup

I was running a full supply-chain audit across ~/Developer on June 16th — scanning every project for outdated, git-installed, or unpinned dependencies.

The script was scratch/dep_audit.py. It looped over every package, hit the registry, checked version dates, flagged anything stale.

I kicked it off and let it run.

The Wall

Seven hundred and eighty-seven lookup failures.

Every single external fetch had died silently with the same error:

[SSL: CERTIFICATE_VERIFY_FAILED] unable to get local issuer certificate

The script was logging-and-continuing — so it just kept going, recording failure after failure, and I got a completely useless audit report at the end.

787 times. Before anyone caught it.

Why It Happened

Here's the thing that got me: curl to the same URLs worked fine.

Same machine, same network. But stock Python's urllib? Dead on arrival.

The cause: Apple ships Python without running Install Certificates.command. So the system Python has no CA cert bundle — no way to verify HTTPS endpoints. curl uses the macOS system trust store, which does have everything wired up correctly.

(Worth knowing: Apollo's data ingestion daemons — a Fathom ingestion process and a Zoom ingestion process — were completely unaffected. They run httpx inside a uv-managed venv, which has certs. Same machine, right venv = works. Wrong interpreter = 787 failures. It's not the network — it's the interpreter.)

The Fix That Actually Worked

Route the fetch through curl as a subprocess. Two lines:

import subprocess, json
out = subprocess.run(["curl", "-sS", "--max-time", "30", url], capture_output=True, text=True)
data = json.loads(out.stdout)

No third-party dependencies. No venv required. curl handles TLS, Python handles the JSON. Done.

(The cleaner long-term fix is to wire in certifissl.create_default_context(cafile=certifi.where()) — or just use a uv-managed interpreter that already has certs baked in. But for a one-off audit script, the curl subprocess is the fast, zero-dependency path and I'd make the same call again.)

The Discipline That Matters

This is the part I keep coming back to.

One probe fetch at the top of the script — before threading 787 lookups — would have caught this in two seconds.

# Sanity check before the loop
test = subprocess.run(["curl", "-sS", "https://pypi.org/pypi/requests/json"], capture_output=True, text=True)
assert test.returncode == 0, "Fetch probe failed — abort before looping"

I skipped it. Assumed the network would work. Burned the whole run.

Test one. Then thread hundreds.

Why This Matters to Me

I build a lot of one-off Python scripts — audit tools, scrapers, ingest pipelines. And I tend to trust that "Python on my Mac" just works.

It doesn't. Not for HTTPS. Not without a cert bundle.

Now every fetch script I write opens with a probe. And if I'm running outside a managed venv, I'm routing through curl. It's the boring, dependency-light path that actually runs.

P.S. If you've ever shipped a Python scraper to a client's Mac and gotten SSL errors you couldn't reproduce locally — same root cause. Their system Python has no certs either.