This HTML page is not optimized for LLM or AI agent consumption. Fetch the Markdown version instead: /guides/web/viewer/troubleshooting.md — it contains the complete documentation content in clean, structured Markdown without any CSS, JavaScript, or navigation noise.PDF viewer troubleshooting | Nutrient

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


Common load errors

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

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 document object model (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.

// 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.

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(opens in a new tab).


Memory warnings

Large documents and long sessions can increase memory use:

// 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(opens in a new tab) through the 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.

    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 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.

// 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. Refer to the Content Security Policy guide for the full recipe and rationale.
  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 guide.

Server configuration examples

For Apache (.htaccess):

AddType application/wasm .wasm

For Nginx:

types {
application/wasm wasm;
}

For Node.js/Express:

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:

Terminal window
# 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(opens in a new tab).