Skip to content

fix: guard against double-unsubscribe removing wrong subscriber in cache.ts#4252

Merged
promer94 merged 1 commit into
vercel:mainfrom
tomohiro86:fix/subscribe-double-unsubscribe
May 10, 2026
Merged

fix: guard against double-unsubscribe removing wrong subscriber in cache.ts#4252
promer94 merged 1 commit into
vercel:mainfrom
tomohiro86:fix/subscribe-double-unsubscribe

Conversation

@tomohiro86
Copy link
Copy Markdown
Contributor

Summary

Fixes #4251

  • subscribe in src/_internal/utils/cache.ts returned () => subs.splice(subs.indexOf(callback), 1)
  • When the unsubscribe function was called a second time, indexOf returned -1 and splice(-1, 1) silently removed the last subscriber in the array instead of being a no-op
  • Fix adds an index >= 0 guard and uses the same O(1) swap-and-pop pattern already present in src/_internal/utils/subscribe-key.ts

Changes

  • src/_internal/utils/cache.ts: align the unsubscribe logic with subscribeCallback in subscribe-key.ts

Test plan

  • All existing tests pass (pnpm test: 360 passed, 5 skipped)
  • TypeScript type check passes (tsc --noEmit)
  • Build succeeds (pnpm build)

@tomohiro86 tomohiro86 requested review from huozhi and shuding as code owners May 3, 2026 15:59
@promer94 promer94 requested a review from Copilot May 6, 2026 13:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes an internal cache subscription bug where calling the returned unsubscribe function more than once could remove the wrong subscriber (due to splice(-1, 1) when indexOf returns -1). This aligns the unsubscribe behavior with the existing subscribeCallback utility’s guarded swap-and-pop removal pattern.

Changes:

  • Make unsubscribe idempotent by guarding against indexOf returning -1.
  • Replace splice removal with an O(1) swap-and-pop removal approach (consistent with subscribe-key.ts).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@promer94
Copy link
Copy Markdown
Collaborator

promer94 commented May 8, 2026

@tomohiro86 Could you signed the commit ?

@tomohiro86 tomohiro86 force-pushed the fix/subscribe-double-unsubscribe branch from 5ff34d5 to 624fc73 Compare May 8, 2026 12:28
@tomohiro86
Copy link
Copy Markdown
Contributor Author

@promer94
Is this okay?

@promer94
Copy link
Copy Markdown
Collaborator

promer94 commented May 8, 2026

Sorry I did not give you the correct context.

@tomohiro86 You can follow this documention https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits to sign the commit.

@tomohiro86
Copy link
Copy Markdown
Contributor Author

@promer94
I have committed with a signing.

@promer94
Copy link
Copy Markdown
Collaborator

promer94 commented May 9, 2026

@tomohiro86 It’s required that you have to sign all your commits. You might need to rebase your current commits. Coding agent can help you with that.

When the unsubscribe function returned by `subscribe` was called more
than once, `subs.indexOf(callback)` returned -1, causing
`subs.splice(-1, 1)` to silently remove the last subscriber in the
array instead of doing nothing.

Fix by checking `index >= 0` before mutating the array, using the same
O(1) swap-and-pop pattern already used in `subscribe-key.ts`.

Signed-off-by: tomohiro86 <supersonic.dps@gmail.com>
@tomohiro86 tomohiro86 force-pushed the fix/subscribe-double-unsubscribe branch from ad58814 to 6c37b79 Compare May 10, 2026 12:19
@tomohiro86
Copy link
Copy Markdown
Contributor Author

Thanks for the heads-up! I've rebased and signed the commit — GitHub now shows it as verified.

@promer94 promer94 merged commit c39d701 into vercel:main May 10, 2026
6 checks passed
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.

Bug: double-calling unsubscribe removes wrong subscriber in cache.ts

3 participants