Skip to content

bug: Chat transport crashes on Safari < 17.4: AbortSignal.any is not a function #5098

Open

Description

@madsobel

Provide environment information

System:
  OS: macOS 27.0.1
  CPU: (12) arm64 Apple M4 Pro
  Memory: 24.00 GB
  Shell: 5.9 - zsh
Binaries:
  Node: 24.12.0
  npm: 11.6.2
  pnpm: 10.33.0
  bun: 1.3.7

Affected client (end user's browser):
Safari 17.2.1 on macOS (Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2.1 Safari/605.1.15)

Packages:
@trigger.dev/sdk 4.8.3 (also reproduced on 4.7.3)
ai 7.0.162
next 16 (App Router), React 19

Describe the bug

The browser-side chat transport (useTriggerChatTransport from @trigger.dev/sdk/chat/react) calls AbortSignal.any without checking that it exists. Safari only added AbortSignal.any in 17.4, so on Safari 17.0–17.3 (and 16.x) every chat request throws:

TypeError: AbortSignal.any is not a function. (In 'AbortSignal.any([t,o.signal])', 'AbortSignal.any' is undefined)
at subscribeToSessionStream

The AI SDK always passes an abortSignal to sendMessages / reconnectToStream, so the AbortSignal.any branch is hit on every send and every resume. Chat is unusable for these users.

Next.js supports Safari 16.4+ by default, so these browsers are still in the supported range for most apps using the SDK.

Unguarded call sites in 4.8.3:

  • dist/esm/v3/chat.js:614 (reconnectToStream)
  • dist/esm/v3/chat.js:1210 (subscribeToSessionStream)
  • dist/esm/v3/chat-client.js:571
    (and the matching commonjs builds)

Reproduction repo

No standalone repo. Any app that uses useTriggerChatTransport with useChat reproduces it on Safari < 17.4, or on any browser after removing the method (see steps below).

To reproduce

  1. Set up a chat using useTriggerChatTransport from @trigger.dev/sdk/chat/react with useChat from @ai-sdk/react.
  2. Open the app in Safari 17.2 (or any Safari < 17.4).
    Alternatively, in any modern browser, run delete AbortSignal.any in the devtools console before the chat mounts.
  3. Send a message, or reload a page with an active chat so it resumes the stream.
  4. The transport throws TypeError: AbortSignal.any is not a function and the chat request fails.

Suggested fix

v3/sessions.js already guards this for Node 18 (if (typeof AbortSignal.any === "function") ... else { wire the caller signal manually }). Applying the same guard, or a small shared helper, to the chat transport would fix it. For example:

function anySignal(signals: AbortSignal[]): AbortSignal {
  if (typeof AbortSignal.any === "function") return AbortSignal.any(signals);

  const controller = new AbortController();
  const aborted = signals.find((s) => s.aborted);
  if (aborted) {
    controller.abort(aborted.reason);
    return controller.signal;
  }

  for (const s of signals) {
    s.addEventListener("abort", () => controller.abort(s.reason), {
      once: true,
      signal: controller.signal,
    });
  }
  return controller.signal;
}

and use it at the three call sites in chat.js and chat-client.js.

Additional information

We've worked around it on our side by polyfilling AbortSignal.any in instrumentation-client.ts. It would still be good to fix in the SDK, since apps using the chat transport won't know they need the polyfill until older-Safari users report broken chat.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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