---
title: "Debug logging for Nutrient Web SDK"
canonical_url: "https://www.nutrient.io/guides/web/troubleshooting/debug-logging/"
md_url: "https://www.nutrient.io/guides/web/troubleshooting/debug-logging.md"
last_updated: "2026-06-10T00:00:00.000Z"
description: "Diagnose where a Nutrient Web SDK load stalls or fails using opt-in debug logging that prints each initialization stage to the console."
---

Nutrient Web SDK includes opt-in debug logging for `NutrientViewer.load()`. When you enable it, the SDK prints a tagged `console.log` line for each initialization stage.

Use debug logging when a load hangs, throws an unexpected error, or never resolves. The console output shows the last stage the SDK reached, which helps you identify whether the issue comes from SDK initialization, worker loading, WebAssembly setup, document loading, rendering, or your application environment.

This guide explains how to:

- Enable debug logging for one load

- Enable debug logging globally

- Read the stage lines

- Interpret common failure patterns

- Decide what to include in a bug report

## Enable debug logging

You can enable debug logging for one `load()` call or for every load after the SDK module evaluates.

### Enable debug logging for one load

Pass `logLevel: 'debug'` or `NutrientViewer.LogLevel.DEBUG` in the configuration object you pass to `NutrientViewer.load()`:

```js

NutrientViewer.load({
  document: "/example.pdf",
  container: "#nutrient-viewer",

  logLevel: NutrientViewer.LogLevel.DEBUG,
});

```

This setting applies only to that `load()` call. Use it when you can edit the call site and need logs for a specific viewer instance.

### Enable debug logging globally

Set `globalThis.NUTRIENT_LOG_LEVEL = 'debug'` before the SDK module evaluates:

```html

<script>
  window.NUTRIENT_LOG_LEVEL = "debug";
</script>
<script src=".../nutrient-viewer.js"></script>

```

For dynamic imports, set the global before importing the SDK.

```js

window.NUTRIENT_LOG_LEVEL = "debug";
await import("@nutrient-sdk/viewer");

```

The global setting applies to every later `load()` call. It also prints a sentinel line when the SDK entry module starts evaluating. That sentinel helps diagnose failures that happen before your code reaches `NutrientViewer.load()`.

### Set the global variable before the SDK loads

Set the global variable before the SDK entry module evaluates. If you set it after the SDK has loaded, debug logging won’t start for the already evaluated module.

For example, pasting `window.NUTRIENT_LOG_LEVEL = 'debug'` into DevTools and then calling `location.reload()` won’t work. Reloading discards the global variable before the SDK module evaluates again.

To toggle the global variable from DevTools, use one of these approaches:

- Navigate to a URL with a query parameter you control, and read that parameter in a script tag that runs before the SDK script tag.

- Use a browser extension that injects the variable at page-load time.

## Read the log lines

When debug logging is on, the browser console shows stage lines like these:

```

[Nutrient #1] load() entered

[Nutrient #1] validating configuration

[Nutrient #1] configuration validated

[Nutrient #1] worker spawned

[Nutrient #1] chunk fetched: standalone

[Nutrient #1] backend selected: standalone

[Nutrient #1] React mounted

[Nutrient #1] WASM instantiated

[Nutrient #1] document opened

[Nutrient #1] load() resolved

[Nutrient #1] initial render complete

```

### Line prefix and counter

Each per-load line uses a `[Nutrient #N]` prefix. `#N` increments with each `NutrientViewer.load()` call in the current page session.

Use the counter to distinguish concurrent loads. For example, `loadTextComparison()` runs two `load()` calls in parallel, so the console can show `[Nutrient #1]` and `[Nutrient #2]` lines interleaved.

The counter only indicates order within the current page session. A page reload resets it.

### Stages

A successful load can include the following stages. The order can vary based on the backend and whether the browser has already cached the chunk.

| Stage                          | Meaning                                                                                                                                                                                         |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `load() entered`               | Your code called `NutrientViewer.load()`.                                                                                                                                                       |
| `validating configuration`     | The SDK is about to run synchronous validation on the configuration object.                                                                                                                     |
| `configuration validated`      | Synchronous checks passed. These include legacy Edge guards, nonce format checks, and deprecation warnings. Container resolution, license validation, and backend-specific checks happen later. |
| `worker spawned`               | Any in-flight `NutrientViewer.preloadWorker()` call has settled. If you didn’t call `preloadWorker()`, the SDK spawns the worker during the next stage.                                         |
| `chunk fetched: standalone`    | The SDK fetched the standalone backend chunk over the network for the first time.                                                                                                               |
| `chunk cached: standalone`     | The SDK reused the standalone backend chunk from a previous load.                                                                                                                               |
| `chunk fetched: server`        | The SDK fetched the server backend chunk.                                                                                                                                                       |
| `backend selected: standalone` | The SDK constructed the standalone backend instance.                                                                                                                                            |
| `backend selected: server`     | The SDK constructed the server backend instance.                                                                                                                                                |
| `React mounted`                | The SDK mounted the viewer’s React tree into the container.                                                                                                                                     |
| `WASM instantiated`            | The SDK instantiated the WebAssembly module and can call into it. This stage applies to standalone mode.                                                                                        |
| `GdPicture initialized`        | The SDK initialized GdPicture for the current load. This stage appears only for Office document loads.                                                                                          |
| `document opened`              | The engine parsed the document.                                                                                                                                                                 |
| `load() resolved`              | `NutrientViewer.load()` is about to return the `Instance` to your code.                                                                                                                         |
| `initial render complete`      | The first page finished painting to canvas.                                                                                                                                                     |

Keep these ordering details in mind:

- `chunk fetched: standalone` changes to `chunk cached: standalone` on later standalone loads when the backend module has already been imported. The same applies after `NutrientViewer.preloadWorker()` has run. Each standalone load shows one of those two stages.

- `initial render complete` fires after `document opened`, but its position relative to `load() resolved` depends on the environment. In standalone mode, it can interleave with post-`connect()` setup. In server mode, it usually appears after `load() resolved`.

### Failed loads

If a load fails, the SDK prints a final `failed during init` line:

```

[Nutrient #1] failed during init { lastStage: 'WASM instantiated', error: PSPDFKitError:... }

```

`lastStage` shows the stage the SDK reached before the failure. The `error` field contains the original `Error` object, so DevTools can show the full stack trace.

### Aborted loads

If an `AbortSignal` cancels a load, the SDK prints one final `aborted by signal` line.

```

[Nutrient #1] aborted by signal { lastStage: 'React mounted' }

```

The SDK logs the abort once. It doesn’t print a separate `failed during init` line for the same load. It also suppresses teardown errors and stage lines from callbacks that finish after the abort.

## SDK module evaluated sentinel

When you enable the global setting before the SDK loads, the SDK prints one additional line at the top of its entry module:

```

[Nutrient] SDK module evaluated

```

This line doesn’t include a `#N` counter because it fires before any `NutrientViewer.load()` call. The SDK emits it before any other code in the entry module runs.

Use the sentinel to identify whether the SDK entry module evaluated:

- If you see `[Nutrient] SDK module evaluated`, the SDK entry module evaluated. If loading still fails or hangs, inspect the per-load `[Nutrient #N]` stage lines that follow.

- If you don’t see `[Nutrient] SDK module evaluated`, the SDK entry module didn’t evaluate. Look upstream of the SDK. Common causes include build-tool errors, failed chunk loads, and dynamic `import()` calls that never settle.

The sentinel helps expose silent failures where execution never reaches `NutrientViewer.load()`.

## Common failure patterns

The following patterns describe common console output and where to investigate next.

### No logs appear

You set `globalThis.NUTRIENT_LOG_LEVEL = 'debug'` before the SDK loads and reload the page, but the console remains empty. You don’t see the sentinel or any stage lines.

This means the SDK entry module didn’t evaluate. An upstream layer prevented the SDK from reaching its first executable line.

Check the following areas:

- Open the browser Network tab and confirm `nutrient-viewer.js` and its chunks loaded with a `200` status.

- Check the console for parse errors or `SyntaxError` entries that appeared before your script tag ran. Some bundlers can transform the UMD bundle into syntax older parsers reject. One known case is Turbopack UMD re-minification in Next.js 16, which can produce invalid `new Foo?.()` optional-chain expressions that V8 rejects at parse time.

- Confirm the dynamic `import()` of the SDK resolved. If the import promise never resolves or rejects, a surrounding `try`/`catch` won’t run.

### Logs stop and load never resolves

You see stage lines up to one point, and then logging stops. You don’t see `failed during init`, `aborted by signal`, or `load() resolved`.

This means an `await` in the SDK initialization flow is hanging without rejecting. Use the last visible stage to identify the boundary where initialization stopped.

Check the relevant area based on the last visible stage:

- **Stopped at `worker spawned`** — The standalone backend chunk’s dynamic import is hanging. Check the Network tab for an in-flight request for the `nutrient-viewer-standalone.*.js` chunk, and confirm your `baseUrl` is reachable.

- **No stage lines after `[Nutrient] SDK module evaluated`** — A pending `NutrientViewer.preloadWorker()` call may be hanging on the worker fetch, and `load()` is waiting for it. Confirm the worker file is reachable from the page’s origin.

- **Stopped at `WASM instantiated`** — The engine initialized, but `document opened` didn’t fire. The document fetch is hanging. Confirm the `document` URL responds. In server-backed deployments, confirm `documentId` is valid and the JWT hasn’t expired.

- **Stopped at `document opened`** — The document parsed, but post-load setup is stuck. This setup can include the annotation provider, form fields, optional content group (OCG) layers, or embedded files. Check the Network tab for in-flight requests.

- **Stopped at `load() resolved`** — `load()` resolved, but `initial render complete` didn’t fire. The React tree mounted, but canvas rendering is stuck. Confirm the container has nonzero dimensions and isn’t `display: none`.

### Read the failure stack trace

The `failed during init` line includes the original `Error` object. Expand it in DevTools to view the full stack trace.

Use the stack trace this way:

- Frames near the top usually come from Nutrient Web SDK.

- Frames near the bottom usually come from your application.

- The `message` field usually gives the most actionable detail.

If the message reads `Failed to initialize PSPDFKit: Invalid license key`, check the license string, the activation domain, and whether the environment can reach the activation server.

If the message names a file, such as `Couldn't fetch the file: Not Found`, check the URL, server response, and cross-origin resource sharing (CORS) headers.

## Performance impact

Debug logging is opt-in and off by default.

When logging is off, each stage call only performs one truthiness check. The SDK doesn’t allocate logging data, call the console, or produce console output.

When logging is on, the main cost comes from `console.log` calls and browser console rendering. You can leave the global setting enabled during a production debug session.

## File a bug report

If debug logging identifies a failure pattern, include the full console output in your bug report. Useful output includes:

- A `failed during init` line with the stack trace

- A hung load with the last visible stage

- An absent SDK-module-evaluated sentinel

- Relevant Network tab failures

For more information, refer to the [bug reporting](https://www.nutrient.io/guides/web/troubleshooting/bug-reporting.md) guide.

## Related guides

Use these guides with debug logging when you narrow down the failure area:

- For support requests and diagnostic attachments, refer to the [bug reporting](https://www.nutrient.io/guides/web/troubleshooting/bug-reporting.md) guide.

- For common integration and rendering issues, refer to the [common issues](https://www.nutrient.io/guides/web/troubleshooting/common-issues.md) guide.

- For license activation failures, refer to the [license troubleshooting](https://www.nutrient.io/guides/web/troubleshooting/license-troubleshooting.md) guide.

- For asset chunk loading failures, refer to the [`ChunkLoadError` troubleshooting](https://www.nutrient.io/guides/web/troubleshooting/chunkloaderror-during-pspdfkit-to-nutrient-migration-in-ember/) guide.

- For configuration options used by `NutrientViewer.load()`, refer to the [`NutrientViewer.Configuration` API reference](https://www.nutrient.io/api/web/NutrientViewer.Configuration.html).
---

## Related pages

- [Bug Reporting](/guides/web/troubleshooting/bug-reporting.md)
- [Chunkloaderror During Pspdfkit To Nutrient Migration In Ember](/guides/web/troubleshooting/chunkloaderror-during-pspdfkit-to-nutrient-migration-in-ember.md)
- [Content Security Policy](/guides/web/troubleshooting/content-security-policy.md)
- [Fixing Split Undefined Error With Npm Build](/guides/web/troubleshooting/fixing-split-undefined-error-with-npm-build.md)
- [Fixing Symbol Iterator Error](/guides/web/troubleshooting/fixing-symbol-iterator-error.md)
- [npm](/guides/web/troubleshooting/nightlies.md)
- [This will make the current directory contents available through `http://0.0.0.0:5000`.](/guides/web/troubleshooting/common-issues.md)
- [Testing Troubleshooting](/guides/web/troubleshooting/testing-troubleshooting.md)
- [Webassembly Simd Support](/guides/web/troubleshooting/webassembly-simd-support.md)
- [Typescript](/guides/web/troubleshooting/miscellaneous/typescript.md)

