The Deploy That Never Deployed

Published May 14, 2026Updated May 14, 20263 min read

By Junaid Ahmed


I merged a pull request. The functions didn't deploy.

That sentence is the whole post if you want the short version. The long version is more useful, because the bug had been sitting there for months, and I had been deploying around it without noticing.


The shape of the silence

PodGlue has a GitHub Actions workflow that deploys Supabase edge functions whenever code under supabase/functions/ lands on main. Standard "push to main, CI ships it" pattern. I wrote it months ago. I never had a reason to look at it after that.

This week I shipped a Kit integration, five new edge functions. The merge landed clean. The functions didn't appear. The admin app started throwing "Load failed" because the function it was trying to call didn't exist on the server.

I ran supabase functions deploy from my laptop and shipped them by hand in 30 seconds. Problem solved in the moment.

But I went looking for why CI hadn't fired.


What was in the YAML

The error GitHub finally surfaced when I clicked through:

Failed to queue workflow run:

Unrecognized named-value: 'secrets'.

Located at position 1 within expression:

 secrets.SLACK_OPS_WEBHOOK_URL != ''

The workflow had a Slack-notify step at the bottom, the kind you add once and forget. It was guarded by an if: condition that referenced secrets.SLACK_OPS_WEBHOOK_URL. GitHub Actions does not allow the secrets context inside step-level if: expressions. The parser refused to load the file. The workflow couldn't even queue.

Every push to main that touched edge functions had silently failed to trigger CI. For months.


The bug I had built around

The fix took five lines. Map the secret to env: and check the env var inside the script instead of inside the if:. Standard, boring, well-documented.

What actually bothered me was the months of unnoticed failure.

I'd been deploying edge functions by hand the whole time. I had a script. The script worked. The CI was theoretically backing me up. Every time I ran the script I assumed CI was running too, behind the scenes, keeping me honest. It wasn't. It hadn't been for a long time.

The lesson here is not watch your CI more carefully.

The lesson is that silence in a system is data.


What silence usually means

I logged 1,500 miles on the bike in 2017. About half of those were with my cycling team, Velocipede, weekly group rides through Virginia roads, twenty or thirty of us in a paceline, taking turns at the front.

The thing about a paceline is you stop noticing your own bike. You're listening to the rider ahead of you, the rider behind, the road, the wind. The small sounds your own frame makes, a click in the bottom bracket, a brake pad that's worn thin, a creak in the seatpost, go into the same background hum as everything else. You ride for an hour with something quietly going wrong and you don't hear it until you stop and someone in your group asks what was that noise?

Cyclists don't usually crash because a part snapped. They crash because something had been slowly going wrong and they'd tuned it out.

CI is the same. The green check next to your last merge is supposed to be the signal that everything ran. If the check never showed up, that's the signal too, but you have to notice the absence, which is harder than noticing a failure. We're wired to react to red. We're not wired to react to nothing.


What I changed

I fixed the workflow. The Slack step now lives inside a shell script that exits cleanly if no webhook is configured. The if-secrets pattern is gone.

I also went and looked at every other workflow file in the repo. None of them had the same bug. Small mercy.

Future me will not hit this trap again. But it's the same kind of "future me" who's also riding through a slow leak right now and doesn't know it. There's always a quiet thing going wrong somewhere. The job is to listen for it.


PodGlue ships small fixes constantly. The infrastructure ones don't make the changelog. They're the difference between a product that quietly works and a product that quietly doesn't, and the cost of missing them compounds in the silence.

I merged a pull request. The functions didn't deploy. Most of the lesson was in everything I hadn't noticed before that one.

Junaid Ahmed is the host of Hacks & Hobbies and the founder of PodGlue.

Ready to make every episode compound?

PodGlue is the operating system for relationship-driven podcasters.

Get Started Free

Related reading