Skip to content

fix(actions): prevent unhandledRejection crash on WorkOS refresh failure#48

Merged
acmeguy merged 1 commit intomainfrom
fix/actions-token-unhandled-rejection
Apr 23, 2026
Merged

fix(actions): prevent unhandledRejection crash on WorkOS refresh failure#48
acmeguy merged 1 commit intomainfrom
fix/actions-token-unhandled-rejection

Conversation

@acmeguy
Copy link
Copy Markdown

@acmeguy acmeguy commented Apr 23, 2026

Summary

  • Attach .catch(() => {}) to the singleflight .finally() chain in services/actions/src/auth/token.js so cleanup cannot produce a dangling rejected promise.
  • The awaited consumer still owns error handling; this fix only addresses the orphan chain.

Context

Observed in production (synmetrix k8s ns): both synmetrix-actions replicas crashed with exit 1 when WorkOS returned invalid_grant — Session has already ended from authenticateWithRefreshToken. Stack pointed at src/auth/token.js:66.

Root cause: the singleflight pattern stored the refresh promise, then called refreshPromise.finally(() => inflightRefreshes.delete(sessionId)) on a separate statement. That .finally() returns a new promise which re-rejects if the source rejects. No handler was attached to it, so unhandledRejection fired even though await refreshPromise inside the try/catch handled its own chain.

Test plan

  • Deploy to staging, force a refresh with an expired WorkOS session (or invalidate a refresh token), confirm process stays up and /auth/token returns 200 with cleared workosAccessToken (falls through to existing Hasura JWT path).
  • Verify no regression in the happy-path token refresh.

🤖 Generated with Claude Code

The singleflight `.finally()` chain created a dangling promise with no
error handler. When `authenticateWithRefreshToken` rejected (e.g. expired
session), the finally chain re-rejected independently of the awaited
consumer, tripping unhandledRejection and crashing the process.

Attach `.catch(() => {})` to the cleanup chain. The awaited consumer
still owns the real error handling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@acmeguy acmeguy merged commit 61fd340 into main Apr 23, 2026
3 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.

2 participants