|
| 1 | +# Repeated `Sentry.init()` Calls |
| 2 | + |
| 3 | +This document records how `Sentry.init()` should act when an app calls it |
| 4 | +more than once. Use it when you add or change an `init()` in any SDK. |
| 5 | + |
| 6 | +## The rule |
| 7 | + |
| 8 | +> One active client per `init()` target. The first `init()` wins. A later |
| 9 | +> `init()` changes nothing, returns the active client, and warns. To |
| 10 | +> reconfigure, call `close()` first. |
| 11 | +
|
| 12 | +"Active" means a client is bound to the current scope. `Sentry.close()` |
| 13 | +closes the client and unbinds it, so a later `init()` sets up a new client. |
| 14 | + |
| 15 | +A repeated `init()` is not supported. Until the next major version, most |
| 16 | +SDKs still replace the client (see below). Do not depend on that. |
| 17 | + |
| 18 | +## Why |
| 19 | + |
| 20 | +When `init()` replaces a client, nothing closes the old one: |
| 21 | + |
| 22 | +- Buffered logs, metrics, spans, client reports, and flush timers stay on |
| 23 | + the old client. |
| 24 | +- `setupOnce` runs only for the first client, because the list of |
| 25 | + installed integrations is global. The result mixes settings from both |
| 26 | + calls. |
| 27 | +- `initialScope` merges into the current scope on each call. |
| 28 | + |
| 29 | +"First wins" never gives a user half of one config and half of another. |
| 30 | + |
| 31 | +## Current behavior |
| 32 | + |
| 33 | +| Entry point | Repeated call | |
| 34 | +| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| 35 | +| `initAndBind` (browser and its wrappers, Deno), Node `_init`, Vercel Edge | Warns, then replaces the client. Returns the new client. | |
| 36 | +| Next.js server, Remix server, Hono Node | Keeps the first client and returns it. Logs in debug mode only. | |
| 37 | +| Hono Bun and Deno | Keeps the first client and returns it. Warns with its own text. | |
| 38 | +| Nuxt server | Keeps the first client and returns it. Logs that a `--import` preload is no longer needed. | |
| 39 | +| Cloudflare (default) | Keeps the first client of the isolate and returns it. Closing that client clears the cache. `cacheClient: false` makes a new client on each call, with no warning. | |
| 40 | +| Next.js edge | Warns, then replaces the client. Returns `void`. | |
| 41 | + |
| 42 | +The shared warning lives in `warnIfClientIsActive()` in |
| 43 | +`packages/core/src/sdk.ts`. Core exports it as |
| 44 | +`_INTERNAL_warnIfClientIsActive` for SDKs that build their client without |
| 45 | +`initAndBind`. |
| 46 | + |
| 47 | +A wrapper that expects a repeated call, such as a server bundle and a |
| 48 | +`--import` preload that both run the config, keeps its own guard and |
| 49 | +returns early. The shared warning then does not show. |
| 50 | + |
| 51 | +## TODO(v12): Plan for the next major version |
| 52 | + |
| 53 | +1. Move the "first wins" guard into `initAndBind`, Node's `_init`, and |
| 54 | + Vercel Edge's `init`. Remove the guards in each wrapper. |
| 55 | +2. Switch browser to "first wins". For two apps on one page, point users |
| 56 | + to separate clients that are not bound with `init()` (see #24883). |
| 57 | +3. Make Next.js edge return the client. |
| 58 | + |
| 59 | +## Tests |
| 60 | + |
| 61 | +A test that calls `init()` again without a reset now prints the warning. |
| 62 | +Reset between tests with one of these: |
| 63 | + |
| 64 | +- `getCurrentScope().setClient(undefined)`, or a helper that clears the |
| 65 | + carrier (`getMainCarrier().__SENTRY__ = undefined`). |
| 66 | +- `await Sentry.close()`. This also flushes, so it is slower. |
| 67 | + |
| 68 | +The warning goes through `consoleSandbox`, which calls the method stored |
| 69 | +in `originalConsoleMethods`. To assert on it, replace |
| 70 | +`originalConsoleMethods.warn` with a mock. A spy on `console.warn` misses |
| 71 | +it once the console integration is set up. |
0 commit comments