Skip to content

fix(functions): clean up cross-signal abort listener on invoke() return#2487

Merged
kallebysantos merged 1 commit into
supabase:masterfrom
FrancoKaddour:fix/functions-abort-listener-leak
Jul 20, 2026
Merged

fix(functions): clean up cross-signal abort listener on invoke() return#2487
kallebysantos merged 1 commit into
supabase:masterfrom
FrancoKaddour:fix/functions-abort-listener-leak

Conversation

@FrancoKaddour

Copy link
Copy Markdown
Contributor

When invoke() is called with both timeout and signal, an event listener is registered on the caller's AbortSignal to forward aborts to the internal timeoutController. That listener was never removed, so callers that reuse the same AbortController across multiple invocations accumulate dangling listeners — keeping the timeoutController alive indefinitely.

Root cause: the listener was created as an inline arrow function () => timeoutController!.abort()), so no reference existed to pass to removeEventListener.

Fix: store the listener in onAbort before registering it, and call options.signal?.removeEventListener('abort', onAbort) in the finally block so it's cleaned up on every code path (success, error, and abort).

Two unit tests are included that assert the same function reference is passed to both addEventListener and removeEventListener.

When invoke() is called with both timeout and signal, an event listener
is added to the caller's AbortSignal to propagate abort to the internal
timeoutController. Previously that listener was never removed, leaving a
stale reference to the timeoutController alive for the lifetime of the
signal.

Now the listener is stored in onAbort and removed in the finally block,
so callers that reuse the same AbortController across multiple invocations
do not accumulate dangling listeners.
@FrancoKaddour
FrancoKaddour requested review from a team as code owners July 2, 2026 13:21
@pkg-pr-new

pkg-pr-new Bot commented Jul 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@supabase/auth-js

npm i https://pkg.pr.new/@supabase/auth-js@2487

@supabase/functions-js

npm i https://pkg.pr.new/@supabase/functions-js@2487

@supabase/postgrest-js

npm i https://pkg.pr.new/@supabase/postgrest-js@2487

@supabase/realtime-js

npm i https://pkg.pr.new/@supabase/realtime-js@2487

@supabase/storage-js

npm i https://pkg.pr.new/@supabase/storage-js@2487

@supabase/supabase-js

npm i https://pkg.pr.new/@supabase/supabase-js@2487

commit: ac3d341

@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 94.421% (+14.1%) from 80.303% — FrancoKaddour:fix/functions-abort-listener-leak into supabase:master

@kallebysantos
kallebysantos merged commit 9e8c573 into supabase:master Jul 20, 2026
26 checks passed
@FrancoKaddour

Copy link
Copy Markdown
Contributor Author

Thanks for the review and merge, @kallebysantos! 🙌

mandarini pushed a commit to supabase/supabase that referenced this pull request Jul 22, 2026
This PR updates @supabase/*-js libraries to version 2.110.8.

**Source**: supabase-js-stable-release

**Changes**:
- Updated @supabase/supabase-js to 2.110.8
- Updated @supabase/auth-js to 2.110.8
- Updated @supabase/realtime-js to 2.110.8
- Updated @supabase/postgest-js to 2.110.8
- Refreshed pnpm-lock.yaml

---

## Release Notes

## v2.110.8

## 2.110.8 (2026-07-21)

### 🩹 Fixes

- **auth:** downgrade aborted/transient fetch failures from
console.error to warn
([#2544](supabase/supabase-js#2544))
- **functions:** clean up cross-signal abort listener on invoke() return
([#2487](supabase/supabase-js#2487))
- **functions:** match response Content-Type case-insensitively
([#2515](supabase/supabase-js#2515))
- **storage:** url-encode object key in CDN purge methods
([#2545](supabase/supabase-js#2545))
- **supabase:** skip Node warning in Deno
([#2541](supabase/supabase-js#2541))

### ❤️ Thank You

- Franco Kaddour @FrancoKaddour
- Katerina Skroumpelou @mandarini
- Pedro Henrique
- Vaibhav @7ttp
## v2.110.7

## 2.110.7 (2026-07-16)

### 🩹 Fixes

- **postgrest:** correct self-reference inference
([#2525](supabase/supabase-js#2525))
- **realtime:** trigger set auth on INITIAL_SESSION event
([#2531](supabase/supabase-js#2531))
- **realtime:** update phoenix to fix presence issue
([#2532](supabase/supabase-js#2532))

### ❤️ Thank You

- Eduardo Gurgel
- Filipe Cabaço @filipecabaco
- Vaibhav @7ttp

This PR was created automatically.

Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com>
mandarini pushed a commit to supabase/ssr that referenced this pull request Jul 22, 2026
This PR updates `@supabase/supabase-js` to v2.110.8.

**Source**: supabase-js-stable-release

---

## Release Notes

## v2.110.8

## 2.110.8 (2026-07-21)

### 🩹 Fixes

- **auth:** downgrade aborted/transient fetch failures from
console.error to warn
([#2544](supabase/supabase-js#2544))
- **functions:** clean up cross-signal abort listener on invoke() return
([#2487](supabase/supabase-js#2487))
- **functions:** match response Content-Type case-insensitively
([#2515](supabase/supabase-js#2515))
- **storage:** url-encode object key in CDN purge methods
([#2545](supabase/supabase-js#2545))
- **supabase:** skip Node warning in Deno
([#2541](supabase/supabase-js#2541))

### ❤️ Thank You

- Franco Kaddour @FrancoKaddour
- Katerina Skroumpelou @mandarini
- Pedro Henrique
- Vaibhav @7ttp

This PR was created automatically.

Co-authored-by: supabase-workflow-trigger[bot] <266661614+supabase-workflow-trigger[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants