Repository: mozilla/pdf.js (2025-08-09T20:35:46Z)

Issue:
[Bug]: Failed to convert napi value Object into rust type `f64`
### Attach (recommended) or Link to PDF file

[eee06a39-b040-4c57-8ec9-7afd718c6aa0.pdf](https://github.com/user-attachments/files/21622995/eee06a39-b040-4c57-8ec9-7afd718c6aa0.pdf)

### Web browser and its version

-

### Operating system and its version

macOS 15.5 (24F74)

### PDF.js version

5.4.54

### Is the bug present in the latest PDF.js version?

Yes

### Is a browser extension

No

### Steps to reproduce the problem

```typescript
import * as pdfjs from 'pdfjs-dist/legacy/build/pdf.mjs';

interface ExtractOptions {
  pages?: number[];
  maxSize?: number;
  quality?: number;
  fit?: 'inside' | 'outside';
}

async function extractImages(pdfBuffer: Buffer, options: ExtractOptions) {
  const loadingTask = pdfjs.getDocument({
    data: new Uint8Array(pdfBuffer),
    cMapUrl: '/opt/nodejs/node_modules/pdfjs-dist/cmaps/',
    cMapPacked: true,
    standardFontDataUrl: '/opt/nodejs/node_modules/pdfjs-dist/standard_fonts/',
    // enableHWA: true,
    // verbosity: pdfjs.VerbosityLevel.INFOS,
  });
  const pdfDocument = await loadingTask.promise;

  // if no pages are specified, use [0, ..., numPages - 1]
  const pages = options?.pages || new Array(pdfDocument.numPages).fill(0).map((_, i) => i + 1);

  const images: Buffer[] = [];

  for (const index of pages) {
    console.log('Rendering page', index, 'of', pages[pages.length - 1], '...');

    const page = await pdfDocument.getPage(index);

    // calculate viewport scale based on max dimension
    const maxDimension = options?.maxSize || 4096;
    const initialViewport = page.getViewport({ scale: 1.0 });
    if (!initialViewport.width || !initialViewport.height) {
      throw new Error('Invalid viewport dimensions');
    }

    const scale = (options?.fit === 'outside' ? Math.max : Math.min)(
      maxDimension / initialViewport.width,
      maxDimension / initialViewport.height,
    );
    const viewport = page.getViewport({ scale });

    // render page
    const canvasAndContext = (pdfDocument.canvasFactory as any).create(viewport.width, viewport.height);
    const renderTask = page.render({
      canvas: canvasAndContext.canvas,
      canvasContext: canvasAndContext.context,
      viewport: viewport,
      intent: 'print',
    });
    await renderTask.promise;
    page.cleanup();

    // retrieve image
    const image = canvasAndContext.canvas.toBuffer('image/jpeg', {
      quality: (options?.quality || 80) / 100,
    });

    images.push(image);
  }

  void pdfDocument.cleanup();
  return images;
}
```

### What is the expected behavior?

-

### What went wrong?

```console
Rendering page 1 of 1 ...
Info: page=1 - getOperatorList: time=62ms, len=749
file:///Users/robertmainzer/Workspace/ec2-express-backend/node_modules/pdfjs-dist/legacy/build/pdf.mjs:14431
      ctx.setLineDash(dashArray);
          ^

Error: Failed to convert napi value Object into rust type `f64`
    at CanvasGraphics.setDash (file:///Users/robertmainzer/Workspace/ec2-express-backend/node_modules/pdfjs-dist/legacy/build/pdf.mjs:14431:11)
    at CanvasGraphics.executeOperatorList (file:///Users/robertmainzer/Workspace/ec2-express-backend/node_modules/pdfjs-dist/legacy/build/pdf.mjs:14243:20)
    at InternalRenderTask._next (file:///Users/robertmainzer/Workspace/ec2-express-backend/node_modules/pdfjs-dist/legacy/build/pdf.mjs:19634:37) {
  code: 'NumberExpected'
}

Node.js v22.12.0
```

### Link to a viewer

_No response_

### Additional context

Code works for _all_ pdf files, except this one.

In a web environment, the code works for the pdf file and no error is thrown. This appears only in Node.js, even though the file is exactly the same.


Discussion:
This is likely a bug with the implementation of setLineDash in https://github.com/Brooooooklyn/canvas
@nicolo-ribaudo thanks for the hint! I’ve opened an issue there as well: https://github.com/Brooooooklyn/canvas/issues/1096 
While the error is caused by a `@napi-rs/canvas` bug (which should ignore the invalid data rather than throwing), there might be _also_ a problem on the PDF.js side, since the array it's passing to `setLineDash` is
```js
[
  { cmd: "n" },
  { cmd: "one" }
]
```
rather than an array of numbers.



Patch:
diff --git a/src/core/evaluator.js b/src/core/evaluator.js
index 25b32505b8ba0..474f297884b9b 100644
--- a/src/core/evaluator.js
+++ b/src/core/evaluator.js
@@ -2206,6 +2206,22 @@ class PartialEvaluator {
             args[0] = Math.abs(thickness);
             break;
           }
+          case OPS.setDash: {
+            const dashPhase = args[1];
+            if (typeof dashPhase !== "number") {
+              warn(`Invalid setDash: ${dashPhase}`);
+              continue;
+            }
+            const dashArray = args[0];
+            if (!Array.isArray(dashArray)) {
+              warn(`Invalid setDash: ${dashArray}`);
+              continue;
+            }
+            if (dashArray.some(x => typeof x !== "number")) {
+              args[0] = dashArray.filter(x => typeof x === "number");
+            }
+            break;
+          }
           case OPS.moveTo:
           case OPS.lineTo:
           case OPS.curveTo:


Test patch:
diff --git a/test/unit/evaluator_spec.js b/test/unit/evaluator_spec.js
index 643a965f03a47..7ec3056d2338a 100644
--- a/test/unit/evaluator_spec.js
+++ b/test/unit/evaluator_spec.js
@@ -357,6 +357,18 @@ describe("evaluator", function () {
       expect(result.argsArray).toEqual([]);
       expect(result.fnArray).toEqual([]);
     });
+
+    it("should handle invalid dash stuff", async function () {
+      const stream = new StringStream("[ none ] 0 d");
+      const result = await runOperatorListCheck(
+        partialEvaluator,
+        stream,
+        new ResourcesMock()
+      );
+      expect(result.argsArray[0][0]).toEqual([]);
+      expect(result.argsArray[0][1]).toEqual(0);
+      expect(result.fnArray[0]).toEqual(OPS.setDash);
+    });
   });
 
   describe("thread control", function () {