You can't cancel a JavaScript promise (except sometimes you can)

April 7, 2026
Close-up of a push button sign for accessibility on a white wall.
Photo by George Morina on Pexels

The problem

JavaScript promises have no built‑in cancel button. There’s no .cancel(), no universal AbortController hookup, and TC39 famously walked away from a cancellation proposal in 2016 after a blistering debate — cancelling arbitrary code mid‑flight can leave files half‑written and sockets dangling. So how do you stop someone else’s async function at an exact await point, without their code cooperating? Throwing a special InterruptError is the obvious trick, but try/catch ruins the party: a well‑placed catch can swallow your interruption and the function merrily continues. Surprise! Your control flow is now hostage to every try block in the codebase.

The odd hack

Enter a weirder option: return a promise that never resolves, await it, and simply let the suspended async function sit in limbo until the garbage collector reclaims it. No exceptions, no special returns, no catch blocks to outsmart you. It has been reported that Inngest’s TypeScript SDK uses this pattern to interrupt long‑running workflows on serverless platforms — suspend the invocation when the platform’s hard timeout looms, persist state, and later rehydrate without the user’s code ever knowing it was paused. Generators offer a cleaner, more explicit alternative — yield hands control back to the caller by design — but async/await is what most developers actually write today, so this ghostly never‑resolving promise is an ugly, clever bridge.

Why it matters

This is more than an oddity. As serverless and durable‑function patterns proliferate, runtimes need practical ways to checkpoint and resume work under strict execution windows. The never‑resolving promise trick buys that capability without forcing every workflow author to switch to generators or sprinkle cancellation hooks through their code. But it comes with tradeoffs: it leans on quirky JS semantics and GC behavior, and it’s arguably a leaky abstraction — powerful, yes, but not exactly tidy. Want simplicity? You’ll pay for it somewhere down the stack.

Sources: inngest.com, Hacker News