Skip to content

subscribe(): this.#start() missing .catch() causes unhandled promise rejection crash in Node.js/Bun #4736

Description

@tsushanth

Bug

In packages/typescript-client/src/client.ts, the subscribe() method calls this.#start() without .catch():

subscribe(callback, onError = () => {}) {
  const subscriptionId = {}
  this.#subscribers.set(subscriptionId, [callback, onError])
  if (!this.#started) this.#start()   // ← no .catch()
  return () => { this.#subscribers.delete(subscriptionId) }
}

When an unrecoverable error occurs, #start() routes the error to subscribers via #sendErrorToSubscribers() (which calls the registered onError callbacks), then the promise rejects. Because there's no .catch() attached, this rejection is unhandled — crashing Node.js and Bun processes, which treat unhandled rejections as fatal by default.

Why this is inconsistent

The same this.#start() call pattern in PauseLock.onReleased (line 750) already has this exact fix with an explanatory comment:

this.#start().catch(() => {
  // Errors from #start are handled internally via onError.
  // This catch prevents unhandled promise rejection in Node/Bun.
})

The subscribe() path was missed.

Suggested fix

Apply the identical pattern:

if (!this.#started) this.#start().catch(() => {
  // Errors from #start are handled internally via onError.
  // This catch prevents unhandled promise rejection in Node/Bun.
})

No behavior change — errors are already delivered to onError callbacks before the rejection propagates; this only prevents the unnecessary process crash.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions