JIT Solutions

Writing · September 2026

Three bugs that returned 200 OK and did nothing

I shipped a small auction site last week. Three bugs nearly killed it. Each one reported success and did nothing, and none of them showed up on my laptop.

The site takes bids on days of my week. Win a day and your logo goes on the shirt I wear that day for a month. Ten lots, $25 opening bid. The engineering is dull except for the part where it kept lying to me.

1. The email that never sent

The bid endpoint did this:

void sendConfirmation(bid, lot.name).catch(console.error)
return NextResponse.json({ ok: true }, { status: 201 })

Fire and forget. Send the confirmation, let the response go out without waiting. On my laptop it worked every time. In production it never sent one email.

A serverless function freezes the moment it returns a response. Not deprioritized. Frozen. That dangling promise got maybe a millisecond of event loop before the runtime suspended the process, and the outbound request never finished. No error surfaced, because nothing had failed yet. The catchnever ran either. The endpoint returned 201, the bidder read “check your email,” and no email existed.

On a laptop the process keeps running after the response, so the promise resolves and the mail goes out. My dev machine and production disagreed about whether the code worked. Production was right.

await Promise.allSettled([
  sendConfirmation(bid, lot.name).catch(e => console.error(e)),
  notify(result, lot.name).catch(e => console.error(e)),
])

Await it. Keep swallowing the failures, since a mail problem should not void a good bid, but await it.

Every bid on the site needs email confirmation to count. So this was never going to look like a few missing emails. No bid could ever be confirmed, the board would sit empty for three weeks, and the auction would look dead the entire time. Status 201 at every step.

2. The dev fallback that hid a real bug

I gave the storage layer a fallback. Use Postgres when DATABASE_URL is set, otherwise write to a local JSON file so the site runs before a database exists. I thought I was being careful.

What I had built was a way to never run the Postgres code until deploy day. And the Postgres code was wrong:

const { rows } = await sql`SELECT * FROM bids ...`
return rows.map(rowToBid)

@neondatabase/serverless resolves to the row array itself. No .rows wrapper exists. So rows came back undefined and every read threw Cannot read properties of undefined.

I had also written a type annotation asserting the shape I assumed, so TypeScript agreed with me. My tests passed against the JSON path. The bug sat there from the first line I wrote and waited for a real connection string.

A fallback that diverges from production hides the code you most need to check.

3. DMARC routing the mail to spam

With the first two fixed I placed a test bid. The mail provider reported delivered. I found the confirmation in spam.

delivered tells you the receiving server accepted the message. It tells you nothing about the folder. No API will tell you that. Go look.

The cause was a DMARC record I had never read closely:

v=DMARC1; p=none; rua=...; adkim=s; aspf=s; pct=100

aspf=s demands strict SPF alignment. My SPF record authorized Google Workspace. The transactional mail went out through Amazon SES on a subdomain. Strict alignment rejects that, so SPF alignment failed on every message I sent. DKIM still passed, and p=none meant nothing bounced. Gmail weighed the partial failure and filed it away.

Relaxing to adkim=r; aspf=r and adding include:amazonses.com to SPF fixed it. The next test bid arrived in the inbox.

Three systems behaved correctly here. The DNS was valid. The provider delivered. Gmail applied a defensible policy. My mail still ended up where nobody would read it.

The pattern

A runtime lifecycle assumption, a library API assumption, an email authentication assumption. Three unrelated mistakes with one signature:

  • The operation reported success
  • The logs stayed empty
  • My laptop and production disagreed
  • The symptom was absence, not error

You cannot alert on absence. No exception fires, no 500 shows up, no dashboard turns red. The auction would have run three weeks at $0 and I would have concluded that nobody wanted it, when the confirmation emails were the thing nobody was getting.

So I changed what counts as done. Green status codes are not the finish line. Run one real transaction against production and go confirm the side effects landed: the row sits in the database, the email sits in the inbox instead of spam. Three times in one week, the status code and the world disagreed.

The auction this was in service of runs until September 27. Founder Uniform.