---
title: "Common PDF SDK issues | Nutrient"
canonical_url: "https://www.nutrient.io/guides/web/troubleshooting/common-issues/"
md_url: "https://www.nutrient.io/guides/web/troubleshooting/common-issues.md"
last_updated: "2026-06-10T00:00:00.000Z"
description: "Solutions for common issues and errors in Nutrient Web SDK with debugging tips and workarounds."
---

This article lists some of the most common issues encountered while integrating Nutrient Web SDK.

## Styling issues

When you override styling with general selectors (like `svg`, `img`, and `div`), especially in combination with `!important`, be aware this could cause errors in Nutrient Web SDK, and correct rendering can’t be guaranteed.

The most direct way to debug styling issues is to remove your own CSS from the site and see if the styling issue in Nutrient Web SDK remains. If the issues are gone after removing your CSS, add your CSS file again and open the developer tools of your browser to inspect elements that have issues. Toggle off stylings that get added by your CSS file — by eliminating each CSS attribute, you’ll find out what causes the problem.

To override certain styles in Nutrient Web SDK, use the [public CSS classes](https://www.nutrient.io/../../customizing-the-interface/css-customization/).

## “Refused to apply style from CSS file because its MIME type is not a supported stylesheet MIME type” error

This error occurs when — while fetching custom stylesheets — the assets server responds without the proper MIME header set, or if instead of responding with the CSS content, it responds with an HTML page (e.g. the path to the stylesheet is wrong and the server returns a fallback 404 HTML page instead).

Take a look at [this Stack Overflow post for possible solutions](https://stackoverflow.com/questions/48248832/stylesheet-not-loaded-because-of-mime-type).

## The mounting container has no width/height

Nutrient Web SDK requires an explicit width and height for the used container.

To work with your responsive designs, the width or height can be set to 100 percent. However, the height can be set to `100%` only if the parent element has a `height` that isn’t set to `auto`. Otherwise, the height of your container will be resolved to 0px and you’ll get the following error: “The mounting container has no height.” To fix this issue without changing the parent height, use `100vh`, which represents 100 percent of the full viewport height.

## Invalid token

When receiving the “Invalid Token” error, you can debug and verify your token on [jwt.io](https://jwt.io/). You’ll also get an error in the server log, where you can see if the token has expired or if the user has no access for the given document.

For server-backed integrations with short-lived JWTs, handle expiry by implementing [`NutrientViewer.Configuration#onAuthFailed`](https://www.nutrient.io/api/web/NutrientViewer.Configuration.html#onAuthFailed) and calling [`NutrientViewer.Instance#setSession`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#setSession) with a fresh JWT. If `setSession()` isn’t called within 30 seconds during authentication recovery, affected requests fail. For details and examples, refer to the [client authentication and session renewal](https://www.nutrient.io/guides/web/viewer/client-authentication.md) guide.

## Customizing the fit-to-page and fit-to-width toggle button

Since Nutrient Web SDK uses a toggle button to switch between the fit-to-page and fit-to-width zoom modes, use CSS to overwrite the styles and define a different icon for each zoom mode:

```css

/* We're removing the shown `svg` on both buttons. */.PSPDFKit-Toolbar-Button-Fit-To-Page svg,.PSPDFKit-Toolbar-Button-Fit-To-Width svg {
  content: "";
}

/* Then we set our own icons. */.PSPDFKit-Toolbar-Button-Fit-To-Page span {
  content: url(my-custom-fit-to-page-icon.svg);
}.PSPDFKit-Toolbar-Button-Fit-To-Width span {
  content: url(my-custom-fit-to-width-icon.svg);
}

```

## Page is zoomed when using the trackpad

In Microsoft Edge, the webpage is zoomed when using the pinch-to-zoom gesture on the trackpad. This is because of a different way trackpad gestures are handled. To prevent this, you can still disable the native browser zooming by setting the `-ms-content-zooming` property to `none` in the `body` element of your page:

```css

body {
  -ms-content-zooming: none;
}

```

In other browsers, pinch-to-zoom can be prevented by defining the enabled touch actions. By only enabling `pan-x` and `pan-y`, you can prevent the browser from handling pinch and double-tap gestures. Unfortunately, the safest way to prevent this is by defining it for _every_ element. Otherwise, pinch gestures could be emitted by all elements:

```css

* {
  touch-action: pan-x pan-y;
}

```

## “Response has unsupported MIME type” error

When using the standalone deployment in browsers that support WebAssembly streaming instantiation, the `pspdfkit.wasm` file must be served with the correct content type header: `Content-Type: application/wasm`. When the server isn’t configured to do so, you might get an exception:

```

Unhandled promise rejection TypeError: Response has unsupported MIME type

```

Packages like [`serve`](https://github.com/zeit/serve/), which set the correct `Content-Type` for WebAssembly files and are straightforward to get running, can be used to avoid such errors.

You can install `serve` as a project dependency with `npm` or `yarn`, and then you can run it from the project folder:

```bash

npm install serve

# This will make the current directory contents available through `http://0.0.0.0:5000`.

npx serve

```

**Workaround by disabling streaming instantiation**

Add support for the proper WebAssembly MIME type to your web server due to reasons outlined [in this blog post](https://www.nutrient.io/blog/optimize-webassembly-startup-performance/). If you don’t have the resources to do so, disable streaming instantiation by adding the following option to the configuration object passed to `NutrientViewer.load()`:

```js

NutrientViewer.load({
  disableWebAssemblyStreaming: true,
  //... other options
});

```

## Why do I have to manually copy files from node_modules into my app?

Nutrient Web SDK is bundler agnostic (for the same reasons it’s framework agnostic). In fact, it can even be used without a bundler, and Nutrient’s assets can be referenced via `link` and `script` tags.

Additionally, Nutrient Web SDK splits its codebase into multiple files so that specific pieces are loaded lazily, i.e. only when they’re used. If Nutrient provided a single file bundle, its size would be large, and most of the time, this is unacceptable.

The main entry point, `pspdfkit.js`, is usually bundled automatically by tools. However, the `pspdfkit-lib` additional assets need to be copied manually since the host application is not aware of them being loaded lazily.

## I18n: Cannot find translations for "en". Retry or add them manually to NutrientViewer.I18n.messages["en"]

Translations and other assets like the CSS for Nutrient Web SDK are located in the `pspdfkit-lib` folder. When this folder isn’t copied to the same location as your application file that includes `pspdfkit`, then Nutrient Web SDK isn’t able to locate those assets. This is usually an issue with standalone, since the server is already preconfigured to serve those files correctly.

Refer to our guide to find out how to [copy the Nutrient Web SDK assets](https://www.nutrient.io/sdk/web/getting-started.md#copy-the-pspdfkit-for-web-assets).

## Building Angular for production with source maps

When building your Angular application for production with source maps enabled, your build might hang for several minutes while building `./node_modules/pspdfkit/dist/pspdfkit.js`.

To make your build fast again, disable Angular’s [build optimizer](https://www.npmjs.com/package/@angular-devkit/build-optimizer). Setting the `buildOptimizer` option to `false` in the production settings of `angular.json` will do the trick:

```diff

{
  "projects": {
    "<my-project>": {
      "architect": {
        "build": {
          "configurations": {
            "production": {

-             "buildOptimizer": true

+             "buildOptimizer": false
            }
          }
        }
      }
    }
  }
}

```

## Angular app not working as expected in production

This might happen when Angular tries to optimize the already optimized Nutrient library. To fix this, exclude Nutrient from Angular’s optimizer. This can be done by using Nutrient as a UMD module. Make the following change in your `angular.json` file:

```diff

{

+   "scripts": ["./node_modules/pspdfkit/dist/pspdfkit.js"]
}

```

Now you can access `PSPDFKit` using `window.PSPDFKit` instead of importing it as a `CommonJS/ES` module.

## Can I open local or remote files via URL?

Due to security concerns, web browsers don’t enable `fetch()` and `XMLHttpRequest` APIs to access the local file system or other domains. Since Nutrient Web SDK requires those APIs to load required artifacts and PDF files, it also requires a lightweight web server, as [described in the standalone integration guides](https://www.nutrient.io/sdk/web/getting-started.md#prerequisites).

An example error for using `fetch()` with a `file://` URL looks like this:

```

Fetch API cannot load file:///example.pdf. URL scheme must be "http" or "https" for CORS request.

```

A similar error might occur when trying to open a PDF document hosted on another domain. For Nutrient Web SDK to load such a file, the host server must set proper [cross-origin resource sharing (CORS) headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).

If you don’t have control over the target server, you can use a local proxy to it to access the documents.

## “Tainted canvases may not be exported” and “The operation is insecure” errors

One of the following errors may appear during Nutrient’s initialization.

Google Chrome:

```

DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

```

Firefox/Safari:

```

SecurityError: The operation is insecure.

```

In such a scenario, it could be that you’re trying to load a cross-origin image from a [`NutrientViewer.Configuration#renderPageCallback`](https://www.nutrient.io/api/web/NutrientViewer.Configuration.html#renderPageCallback) definition. If that’s the case, make sure to set the `crossOrigin` property of the [`HTMLImageElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement) instance to `anonymous` before setting its `src`:

```js

const img = document.createElement("img");
img.crossOrigin = "anonymous";
img.src = "https://example.com/myimage.png";

NutrientViewer.load({
  renderPageCallback(ctx, pageIndex, pageSize) {
    ctx.drawImage(
      img,
      (pageSize.width - size) / 2,
      (pageSize.height - size) / 2,
    );
  },
  //...
});

```

## PDF ID mismatch error when loading Instant JSON

You might see one of the following errors when importing Instant JSON:

```

PSPDFKitError: Could not instantiate from Instant JSON: Changing PDF ID mismatch.
Please use the same revision of this PDF document that was used to create this Instant JSON.

```

Or:

```

PSPDFKitError: Could not instantiate from Instant JSON: Permanent PDF ID mismatch.

```

**What causes this error**

The `pdfId` in your Instant JSON doesn’t match the current document’s identity. When the document changes, the `pdfId` gets updated to reflect those changes, which means any previously stored `pdfId` values become outdated.

This happens when:

- **Document operations were performed** — You rotated, added, removed, or moved pages after exporting the Instant JSON.

- **The PDF was modified or resaved** — Any structural change to the PDF updates its identity.

- **You’re applying JSON to a different document** — The JSON was created for a different file.

**Solution: Remove the `pdfId` property**

For most web applications, you should remove `pdfId` before persisting Instant JSON. This approach gives you flexibility to apply annotations across document versions without worrying about mismatch errors.

**When exporting (recommended approach):**

```js

// Destructure to exclude `pdfId`.
const {pdfId,...instantJSON} = await instance.exportInstantJSON()
await saveToDatabase(instantJSON) // Save without pdfId

```

**When importing (if you already saved with `pdfId`):**

```js

// Remove `pdfId` before loading.
if (instantJSON.pdfId) {
  delete instantJSON.pdfId;
}

await NutrientViewer.load({
  container: '#container',

  document: documentUrl,
  instantJSON: instantJSON // Now without `pdfId`.
});

```

**Using `applyOperations` (with Document Editing):**

```js

// Remove `pdfId` from stored JSON.
const storedJSON = await loadFromDatabase()
if (storedJSON.pdfId) {
  delete storedJSON.pdfId;
}

instance.applyOperations([
  {
    type: "applyInstantJson",
    instantJson: storedJSON
  }
]);

```

**When to keep `pdfId`**

Only keep `pdfId` if you need strict version control, such as in legal document workflows where annotations must only apply to exact document versions. In most cases, removing it provides better flexibility.

[Learn more about `pdfId` and Instant JSON compatibility](https://www.nutrient.io/guides/web/json/how-it-works/#understanding-pdfid).

## “Content Security Policy: The page’s settings blocked the loading of a resource at inline” errors

If you’re using a Content Security Policy (CSP) to secure your webpage, make sure you’re using the following directives to enable WebAssembly to load:

```

script-src 'self' 'wasm-unsafe-eval';
worker-src blob:;

```

Versions of Nutrient Web SDK prior to 2024.1.0 additionally required `'unsafe-eval'`. Upgrade to 2024.1.0 or later to drop it.

For background on what `'wasm-unsafe-eval'` actually permits, why Document Engine doesn’t avoid it, the Trusted Types policies the SDK publishes, and a forwardable paragraph for your security team, refer to the [Content Security Policy](https://www.nutrient.io/guides/web/troubleshooting/content-security-policy.md) guide.

## IE 11 issues

If you’re using [IIS](https://www.iis.net/) Server, make sure your server is configured to handle `.mem` files. In the case that the browser doesn’t support WebAssembly, Nutrient Web SDK falls back to asm.js and provides a `.mem` file that the application loads during initialization. Read more about how to configure this manually on the [IIS website](https://docs.microsoft.com/en-us/iis/configuration/system.webserver/staticcontent/mimemap).

Internet Explorer 11 is no longer supported in Nutrient Web SDK [as of version 2022.5.](/blog/pspdfkit-web-2022-5-content-editor-and-measurement-tools/) Edge 18 is no longer supported in Nutrient Web SDK [as of version 2023.2.](/blog/pspdfkit-web-2023-2-comment-mentions-notifications/)

## Chunk failing to load

If your browser throws a “414 Request-URI Too Large” error or can’t load the chunk because of the wrong URL, pass the [`baseUrl`](https://www.nutrient.io/api/web/NutrientViewer.Configuration.html#baseUrl) option in the configuration object.

## Digital signature fails to verify on Nutrient but Adobe Acrobat is able to verify it correctly

One possible reason for Nutrient not being able to correctly verify digital signatures on a document is that the required trusted root certificates aren’t loaded when initializing a Nutrient Web SDK instance.

The reason Adobe Acrobat is able to correctly verify the document on the host machine is because it has access to certificates installed on the host. Additionally, it ships with a built-in list of certificates known as the [Adobe Approved Trust List](https://helpx.adobe.com/acrobat/kb/approved-trust-list2.html) (AATL).

Refer to the guide on [how to create custom certificate sets](https://www.nutrient.io/guides/web/signatures/digital-signatures/signature-lifecycle/prepare-the-certificates-for-signing.md) to learn how to use your trusted root certificate files for digital signature validation on Web SDK deployments.

## Reserved size isn’t enough to contain the signature

If, while signing a document, you receive an error in the console that says “Cannot add the container structure because the reserved size is not enough to contain the signature,” it means the certificate size is bigger than expected. Solve this by passing a custom [`placeholderSize`](https://www.nutrient.io/api/web/NutrientViewer.SignaturePreparationData.html) while calling [`instance.signDocument`](https://www.nutrient.io/api/web/NutrientViewer.Instance.html#signDocument). `placeholderSize` is used to override the default size that’s reserved for the signature container. Read more about it in the [digital signatures](https://www.nutrient.io/guides/web/signatures/digital-signatures/signature-lifecycle/sign-a-pdf-document.md) guide.

## NetworkError when attempting to fetch resource

Browsers sometimes throw an error when a `fetch()` call is interrupted. The specific error depends on the browser. Here are some examples of this error observed in various browsers:

- Chrome — `TypeError: Failed to fetch`

- Firefox — `TypeError: NetworkError when attempting to fetch resource`

- Safari — `TypeError: cancelled`

This can happen when the network is down or when a user clicks the stop loading button while the API request is in progress. This means that if you’re getting random reports with these errors, ignore them, as they’re most likely the result of a usual workflow.

Keep in mind that these errors could also indicate a possible [CORS](#can-i-open-local-or-remote-files-via-url) error — “Failed to fetch” errors can also be generated in the case of failed fetch requests due to misconfigured CORS headers. Investigate if you’re getting these errors without any known reason that could have led to canceling the `fetch()` calls.

## Network error net::ERR_BLOCKED_BY_CLIENT

Unspecified network errors such as `net::ERR_BLOCKED_BY_CLIENT` can be thrown when the client blocks network requests. Possible culprits could be browser extensions such as AdBlock or Ghostery, or similar privacy tools. Another cause could be an antivirus or anti-spyware software running on a user’s device or a network proxy.

You can check if the browser extension is causing your issues by running in an incognito mode (but make sure to not have extensions enabled) or in another browser with no extensions installed. If the issue is caused by system- or network-wide antivirus/privacy software, you’ll need to find a way to disable it, or preferably, run it on a separate machine or a separate network.

## Inaccurate text selection via UI

The viewer renders PDF pages as images. When there’s text on the page, this text is rendered as part of the image, using the original font. To enable text selection, Nutrient Web SDK overlays the same text in HTML but makes it transparent using CSS. The only problem with this approach is that the browser might not ship the original fonts in the PDF, in which case it falls back to a generic font. In this case, manual text selection might not be accurate. This is a known issue, and Nutrient is exploring solutions to improve this behavior in the future.

## React/framework-specific debugging

If `NutrientViewer.load()` hangs or stops during initialization while you debug a framework integration, refer to the [debug logging](https://www.nutrient.io/guides/web/troubleshooting/debug-logging.md) guide to identify the last completed initialization stage.

### Debugging loading and dimensions in React

When debugging React integration issues, you can use detailed error handling to identify loading and dimension problems:

```tsx

// Advanced error handling with retry logic and detailed checks.
import { useEffect, useRef, useState } from "react";

function PDFViewer() {
  const containerRef = useRef(null);
  const [status, setStatus] = useState("Loading...");

  useEffect(() => {
    const container = containerRef.current;
    let cleanup = () => {};

    const initializePDF = async () => {
      try {
        setStatus("Waiting for SDK...");

        // Step 1: Wait for SDK with timeout.
        const maxAttempts = 50; // 5 seconds total.
        let attempts = 0;

        while (!window.NutrientViewer && attempts < maxAttempts) {
          await new Promise((resolve) => setTimeout(resolve, 100));
          attempts++;
        }

        if (!window.NutrientViewer) {
          throw new Error(
            "Nutrient Web SDK failed to load from CDN. Check network connection and CDN availability.",
          );
        }

        // Step 2: Verify container dimensions.
        if (!container) {
          throw new Error(
            "Container ref is not available. Ensure useRef is properly initialized.",
          );
        }

        const rect = container.getBoundingClientRect();
        if (rect.width === 0 || rect.height === 0) {
          throw new Error(
            `Container has no dimensions: ${rect.width}x${rect.height}. ` +
              `Check CSS - container needs explicit width/height, not 0x0 pixels. ` +
              `Common issue: remove 'display: flex' and 'place-items: center' from body.`,
          );
        }

        setStatus("Loading PDF...");

        // Step 3: Load PDF with error handling.
        await window.NutrientViewer.load({
          container,
          document: "https://www.nutrient.io/downloads/nutrient-web-demo.pdf",
        });

        setStatus("PDF loaded successfully!");

        cleanup = () => {
          window.NutrientViewer?.unload(container);
        };
      } catch (error) {
        console.error("PDF loading failed:", error);
        setStatus(`Error: ${error.message}`);

        // Log additional debugging info.
        console.log("Debug info:", {
          containerRef:!!container,
          sdkAvailable:!!window.NutrientViewer,
          containerDimensions: container? container.getBoundingClientRect()
            : null,
          userAgent: navigator.userAgent,
        });
      }
    };

    initializePDF();
    return cleanup;
  }, []);

  return (
    <div>
      <div
        style={{
          padding: "10px",
          background: "#f0f0f0",

          borderBottom: "1px solid #ccc",

          fontSize: "14px",
        }}
      >
        Status: {status}
      </div>
      <div
        ref={containerRef}
        style={{
          height: "calc(100vh - 60px)",
          width: "100vw",
          background: "#e0e0e0", // Visual indicator for container.

        }}
      />
    </div>
  );
}

```

### Step-by-step React debugging process

When PDF loading fails in React applications, follow these debugging steps in order.

1. **Verify SDK loading**

   ```tsx

   console.log("NutrientViewer available:",!!window.NutrientViewer);
   console.log(
     "Window object keys:",
     Object.keys(window).filter((k) => k.includes("Nutrient")),
   );
   ```

2. **Check container ref and dimensions**

   ```tsx

   const container = containerRef.current;
   console.log("Container ref:",!!container);
   if (container) {
     const rect = container.getBoundingClientRect();
     console.log("Container dimensions:", rect.width, "x", rect.height);
     console.log("Container styles:", window.getComputedStyle(container));
   }
   ```

3. **Test PDF file accessibility**
   - For local files in Vite: Check if `http://localhost:5173/nutrient-web-demo.pdf` loads in the browser
   - For local files in Create React App: Check if `http://localhost:3000/nutrient-web-demo.pdf` loads
   - For external URLs: Check browser network tab for CORS errors, 403/404 responses
   - Try loading PDF directly in a new browser tab

4. **Check for CSS conflicts**
   - Inspect container element in browser dev tools
   - Look for `display: flex`, `place-items: center` on body element
   - Verify container has non-zero width/height (not `auto` or `0px`)
   - Check if parent elements have proper height constraints

5. **Review console errors for specific patterns**
   - `403 Forbidden` — CDN access issues, try specific version instead of `@latest`
   - `Failed to fetch` — Network/CORS issues, try local PDF file
   - `TypeError: Cannot read property 'load'` — SDK not loaded, check CDN script tag
   - `Container has no dimensions` — CSS dimension issues, see container debugging above

6. **Network and timing issues**
   - Check if you’re behind a corporate firewall blocking CDN
   - Test with a different network connection
   - Try adding longer delays in SDK loading logic
   - Check if ad blockers or browser extensions are interfering
---

## Related pages

- [Bug Reporting](/guides/web/troubleshooting/bug-reporting.md)
- [Content Security Policy](/guides/web/troubleshooting/content-security-policy.md)
- [Chunkloaderror During Pspdfkit To Nutrient Migration In Ember](/guides/web/troubleshooting/chunkloaderror-during-pspdfkit-to-nutrient-migration-in-ember.md)
- [Debug Logging](/guides/web/troubleshooting/debug-logging.md)
- [Fixing Symbol Iterator Error](/guides/web/troubleshooting/fixing-symbol-iterator-error.md)
- [Fixing Split Undefined Error With Npm Build](/guides/web/troubleshooting/fixing-split-undefined-error-with-npm-build.md)
- [Testing Troubleshooting](/guides/web/troubleshooting/testing-troubleshooting.md)
- [npm](/guides/web/troubleshooting/nightlies.md)
- [Typescript](/guides/web/troubleshooting/miscellaneous/typescript.md)
- [Webassembly Simd Support](/guides/web/troubleshooting/webassembly-simd-support.md)

