---
title: "PDF viewer troubleshooting | Nutrient"
canonical_url: "https://www.nutrient.io/guides/web/viewer/troubleshooting/"
md_url: "https://www.nutrient.io/guides/web/viewer/troubleshooting.md"
last_updated: "2026-05-25T14:09:00.406Z"
description: "Learn how to troubleshoot common PDF viewer issues like font rendering and more."
---

Use this guide to troubleshoot common issues when you set up the document viewer.

- [Font rendering](https://www.nutrient.io/guides/web/features/custom-fonts.md)

## Common load errors

If the viewer doesn’t load, check the browser console first.

```js

try {
  const instance = await NutrientViewer.load({
    container: "#pspdfkit",

    document: "document.pdf",
    licenseKey: "YOUR_LICENSE_KEY"
  });
  console.log("Viewer loaded successfully");
} catch (error) {
  console.error("Failed to load viewer:", error.message);

  // Check for specific error types.
  if (error.message.includes("container")) {
    console.error("Container element not found. Ensure the element exists in the DOM.");
  } else if (error.message.includes("document")) {
    console.error("Document could not be loaded. Check the file path and format.");
  } else if (error.message.includes("network")) {
    console.error("Network error. Check your internet connection and server status.");
  }
}

```

Common causes:

- The container element doesn’t exist in the DOM when `load()` runs.

- The document path is wrong, or the file doesn’t exist.

- Required assets (WebAssembly files) aren’t accessible.

- The document is corrupted or uses an unsupported format.

## CORS issues

Cross-origin resource sharing (CORS) errors occur when you load documents or assets from a different domain.

```js

// Diagnose CORS issues.
async function loadWithCORSDiagnostics() {
  const documentUrl = "https://example.com/document.pdf";

  // First, test if the document is accessible.
  try {
    const response = await fetch(documentUrl, { method: "HEAD" });
    if (!response.ok) {
      console.error(`Document not accessible: HTTP ${response.status}`);
      return;
    }
  } catch (error) {
    console.error("CORS or network error:", error.message);
    console.error("Ensure the server includes these headers:");
    console.error("  Access-Control-Allow-Origin: *");
    console.error("  Access-Control-Allow-Methods: GET, HEAD");
    return;
  }

  // If fetch succeeds, proceed with loading.
  try {
    const instance = await NutrientViewer.load({
      container: "#pspdfkit",

      document: documentUrl,
      licenseKey: "YOUR_LICENSE_KEY"
    });
  } catch (error) {
    console.error("Viewer load error:", error);
  }
}

```

To resolve CORS issues:

- Configure your server to send CORS headers, such as `Access-Control-Allow-Origin: *`.

- Use a proxy so documents are served from the same origin.

- For local development, use a local server instead of `file://` URLs.

## License problems

License errors prevent the viewer from loading correctly.

```js

NutrientViewer.load({
  container: "#pspdfkit",

  document: "document.pdf",
  licenseKey: "YOUR_LICENSE_KEY"
}).then(instance => {
  console.log("License valid, viewer loaded");
}).catch(error => {
  if (error.message.includes("license")) {
    console.error("License error detected:", error.message);

    // Common license issues.
    console.log("Troubleshooting steps:");
    console.log("1. Verify the license key is correct (no extra spaces)");
    console.log("2. Check if the license has expired");
    console.log("3. Ensure the domain matches your license");
    console.log("4. For trial licenses, check usage limits");
  }
});

```

Common license issues:

- **Invalid key** — The license key contains typos or extra whitespace.

- **Domain mismatch** — The license is bound to a different domain.

- **Expired license** — The trial or subscription ended.

- **Feature not licensed** — Your license tier doesn’t include the feature.

For licensing help, contact [Nutrient Support](https://support.nutrient.io/hc/en-us/requests/new).

## Memory warnings

Large documents and long sessions can increase memory use:

```js

// Monitor memory usage (Chrome only).
function checkMemoryUsage() {
  if (performance.memory) {
    const used = Math.round(performance.memory.usedJSHeapSize / 1048576);
    const total = Math.round(performance.memory.totalJSHeapSize / 1048576);
    const limit = Math.round(performance.memory.jsHeapSizeLimit / 1048576);

    console.log(`Memory: ${used}MB used / ${total}MB allocated / ${limit}MB limit`);

    if (used > limit * 0.8) {
      console.warn("High memory usage detected!");
    }
  }
}

// Properly unload the viewer when done.
function cleanupViewer(instance) {
  if (instance) {
    NutrientViewer.unload(instance);
    console.log("Viewer unloaded, memory freed");
  }
}

// Example: Load with memory management.
let viewerInstance = null;

async function loadDocument(documentPath) {
  // Unload previous instance first.
  if (viewerInstance) {
    cleanupViewer(viewerInstance);
  }

  viewerInstance = await NutrientViewer.load({
    container: "#pspdfkit",

    document: documentPath,
    licenseKey: "YOUR_LICENSE_KEY"
  });

  checkMemoryUsage();
  return viewerInstance;
}

```

Best practices:

- Always call `NutrientViewer.unload()` when you switch documents or unmount components.

- To cancel a load in progress, pass an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) through the [`signal`](https://www.nutrient.io/api/web/NutrientViewer.Configuration.html#signal) configuration option. When you abort the signal, the load promise rejects with `AbortError`, and the SDK cleans up allocated resources:

  When the signal is aborted, the operation promise rejects with a `DOMException` whose name is `AbortError`. HTTP-based steps (such as document fetch) are canceled at the network level. For WebAssembly/worker-based processing, the promise still rejects immediately, but underlying processing may continue in the background briefly.

  ```js

  const controller = new AbortController();

  NutrientViewer.load({
    container: "#pspdfkit",

    document: "document.pdf",
    signal: controller.signal,
  }).catch((error) => {
    if (error.name === "AbortError") {
      console.log("Load cancelled");
    }
  });

  // Cancel the in-progress load.
  controller.abort();
  ```

- Avoid loading very large documents (100+ MB) on memory-constrained devices.

- For large files, refer to the [streaming](https://www.nutrient.io/guides/web/viewer/streaming.md) guide.

- Monitor memory during development with browser DevTools.

## WebAssembly failures

Nutrient Web SDK uses WebAssembly for rendering. If WebAssembly fails, the viewer won’t load.

```js

// Check WebAssembly support before loading.
function checkWebAssemblySupport() {
  try {
    if (typeof WebAssembly === "object"
        && typeof WebAssembly.instantiate === "function") {
      // Test basic WebAssembly functionality.
      const module = new WebAssembly.Module(
        Uint8Array.of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)
      );
      if (module instanceof WebAssembly.Module) {
        console.log("WebAssembly is supported");
        return true;
      }
    }
  } catch (e) {
    console.error("WebAssembly check failed:", e);
  }

  console.error("WebAssembly is not supported in this browser");
  return false;
}

// Load with WebAssembly diagnostics.
async function loadWithWasmDiagnostics() {
  if (!checkWebAssemblySupport()) {
    alert("Your browser doesn't support WebAssembly. Please use a modern browser.");
    return;
  }

  try {
    const instance = await NutrientViewer.load({
      container: "#pspdfkit",

      document: "document.pdf",
      licenseKey: "YOUR_LICENSE_KEY"
    });
    return instance;
  } catch (error) {
    if (error.message.includes("wasm") || error.message.includes("WebAssembly")) {
      console.error("WebAssembly error:", error.message);
      console.log("Possible causes:");
      console.log("1. WASM files not found - check baseUrl configuration");
      console.log("2. Server not serving.wasm with correct MIME type");
      console.log("3. Content Security Policy blocking WASM execution");
    }
    throw error;
  }
}

```

Common WebAssembly issues:

1. **Missing MIME type** — Ensure your server serves `.wasm` files with `application/wasm`.

2. **CSP restrictions** — Add `“wasm-unsafe-eval”` to your Content-Security-Policy if required.

3. **Incorrect asset path** — Verify that `baseUrl` points to the correct Nutrient asset location.

4. **Browser compatibility** — Use a supported browser. Refer to the [supported browser](https://www.nutrient.io/guides/web/pspdfkit-for-web/browser-support.md) guide.

**Server configuration examples**

For Apache (`.htaccess`):

```apache

AddType application/wasm.wasm

```

For Nginx:

```nginx

types {
    application/wasm wasm;
}

```

For Node.js/Express:

```js

app.use(express.static("public", {
  setHeaders: (res, path) => {
    if (path.endsWith(".wasm")) {
      res.set("Content-Type", "application/wasm");
    }
  }
}));

```

## Microsoft Edge with Enhanced Security Mode

Microsoft Edge versions earlier than 144.0.3719.92 contained a bug that could cause the Web SDK to fail when **Enhanced Security Mode** was enabled. Microsoft fixed this issue.

### Solution

Update Microsoft Edge to version **144.0.3719.92 or later**. Edge usually updates automatically. To check manually:

1. Go to `edge://settings/help`.

2. Install any available updates.

3. Restart Edge.

### Symptoms

In affected Edge versions with Enhanced Security Mode enabled, you may see:

- An SDK initialization failure with a `std::bad_alloc` exception

- Console errors such as `“memory access out of bounds”`

### Workarounds for older versions

If you can’t update Edge yet, use one of the following workarounds.

**For end users** — Add your app domain to the Enhanced Security allow list:

1. Go to `edge://settings/privacy`.

2. Under **Enhance your security on the web**, select **Exceptions**.

3. Add your app domain.

**For developers/testing** — Start Edge with flags that disable the affected optimization:

```bash

# macOS/Linux

/path/to/msedge --js-flags="--jitless --wasm-jitless --no-drumbrake-register-optimization"

# Windows

"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" --js-flags="--jitless --wasm-jitless --no-drumbrake-register-optimization"

```

### Background

A bug in Chromium’s DrumBrake WebAssembly interpreter caused this issue. Edge uses this interpreter when Enhanced Security Mode disables just-in-time (JIT) compilation. The bug affected register optimization for complex WASM binaries. For details, refer to [Chromium Issue #477318781](https://issues.chromium.org/issues/477318781).
---

## Related pages

- [Client authentication and session renewal](/guides/web/viewer/client-authentication.md)
- [Create custom annotation toggle button](/guides/web/viewer/custom-annotation-toggle.md)
- [Embed Web SDK in a dashboard/app shell](/guides/web/viewer/embed-in-dashboard-app-shell.md)
- [JavaScript image viewer library](/guides/web/viewer/images.md)
- [JavaScript PDF viewer library](/guides/web/viewer.md)
- [Enhance PDF viewing with linearized downloading](/guides/web/viewer/linearized-downloads.md)
- [Mobile responsive JavaScript PDF viewer](/guides/web/viewer/mobile-responsive.md)
- [Office document viewing in JavaScript](/guides/web/viewer/office-documents.md)
- [Page layout and scroll options in our JavaScript PDF viewer](/guides/web/customizing-the-interface/document-presentation-options.md)
- [JavaScript Support in our PDF viewer](/guides/web/features/javascript.md)
- [JavaScript PDF viewer library](/guides/web/viewer/pdf.md)
- [PDF document streaming in JavaScript](/guides/web/viewer/streaming.md)
- [Enable or disable permissions in our JavaScript viewer](/guides/web/features/document-permissions.md)
- [Zoom options in our JavaScript PDF viewer](/guides/web/viewer/zooming.md)

