Takumi

Troubleshooting

Fix Takumi import, bundler, font, image, and layout errors using their messages and runtime-specific solutions.

Search this page for the error message from your build or server logs. If the failure depends on your runtime, start with the import table.

Pick the right entry

Check that your import matches the runtime and bundler.

TargetImport
Node.js, Bun, Deno, Cloudflare Workerstakumi-js / takumi-pdf
A Next.js route, either runtimetakumi-js / takumi-pdf/next
A browser bundle, image outputtakumi-js/wasm/no-init plus takumi-js/wasm-url
A browser or web worker bundle, PDFtakumi-pdf/no-init plus takumi-pdf/wasm-url

The default entry follows the export conditions your bundler sets. If it picks the wrong build, use the runtime-specific entry.

Bundler errors

Export default doesn't exist in target module

Load the WebAssembly binary yourself.

takumi-pdf
import init, { render } from "takumi-pdf/no-init";
import wasmUrl from "takumi-pdf/wasm-url";

await init({ module_or_path: wasmUrl });
takumi-js
import { init, Renderer } from "takumi-js/wasm/no-init";
import wasmUrl from "takumi-js/wasm-url";

await init({ module_or_path: wasmUrl });

const renderer = new Renderer();

takumi-js/wasm/no-init exports init by name, not as the default export. Its Renderer takes a node tree. Build one with fromJsx.

The cause is that your browser bundle resolved the entry made for Vite. That entry imports the binary with a ?url suffix, which only Vite understands.

non-ecmascript placeable asset

Keep @takumi-rs/core out of the bundle:

next.config.ts
const config: NextConfig = {
  serverExternalPackages: ["@takumi-rs/core"], 
};

The package holds a native .node addon, which no bundler can inline. takumi-pdf needs no entry here, because it runs on WebAssembly only.

Cannot find module '@takumi-rs/core-42dc295dcb05a7ef'

Add the serverExternalPackages entry above. Then delete .next and start again.

This is the same native addon in dev mode. Turbopack rewrote the specifier to an internal id, which Node.js cannot resolve at runtime.

Cannot find native binding

@takumi-rs/core loads a platform-specific native package, and the one for the current platform is missing. Check package hoisting and the deploy target.

Hoist the native package

A package manager with a virtual store, such as pnpm, must hoist the native binary. Add the pattern, then run pnpm i again.

pnpm-workspace.yaml
publicHoistPattern:
  - "@takumi-rs/core-*"

With pnpm older than 10.5.0, put the setting in .npmrc instead:

.npmrc
public-hoist-pattern[]=@takumi-rs/core-*

Install the package for your deploy target

Package managers install the native package for the machine that runs the install. Installing on macOS and deploying to Linux leaves the Linux package missing. Install it explicitly:

npm install @takumi-rs/core-linux-x64-gnu
TargetPackage
Linux x64 (glibc)@takumi-rs/core-linux-x64-gnu
Linux x64 (musl, Alpine)@takumi-rs/core-linux-x64-musl
Linux arm64 (glibc)@takumi-rs/core-linux-arm64-gnu
Linux arm64 (musl)@takumi-rs/core-linux-arm64-musl
macOS x64@takumi-rs/core-darwin-x64
macOS arm64@takumi-rs/core-darwin-arm64
Windows x64@takumi-rs/core-win32-x64-msvc
Windows arm64@takumi-rs/core-win32-arm64-msvc

Module not found: Can't resolve './takumi_pdf_wasm_bg.js'

On Turbopack, remove the rule that causes it:

next.config.ts
const config: NextConfig = {
  turbopack: {
    rules: { "*.wasm": { type: "wasm" } }, 
  },
};

On webpack or Rspack with target: "node", upgrade instead:

npm install takumi-pdf@latest @takumi-rs/wasm@latest

The rule tells the bundler to instantiate the binary itself. The bundler then looks for wasm-bindgen glue next to the binary, but the package ships the glue in dist and only the binary in pkg.

Module parse failed: Unexpected character '\0'

Upgrade, then build again:

npm install takumi-pdf@latest @takumi-rs/wasm@latest

Rspack parsed the binary as JavaScript, for the same reason as above.

ENOENT: no such file or directory, open '.../pkg/takumi_pdf_wasm_bg.wasm'

Mark the package external for that build:

esbuild
esbuild.build({ external: ["takumi-pdf"] });

The Node.js entry finds the binary with new URL(specifier, import.meta.url). esbuild, Rollup, and Bun's bundler flatten that entry into one file and leave the call alone, so the path points next to your output instead of into node_modules. Vite, webpack, and Turbopack rewrite the call and copy the binary, so they need no change.

Unable to locate Takumi WASM asset for SSR

Keep the package external for SSR:

vite.config.ts
export default { ssr: { external: ["takumi-pdf"] } };

Vite writes the client asset and the server chunk to different directories. The entry checks the usual layouts for the binary, and an external package skips that search. If your framework must bundle the package, open an issue with your output layout.

Render errors

No registered font covers क (U+0915)

Register a font that covers the characters the error names:

Load a Devanagari font
import { googleFonts } from "takumi-js/helpers";
import { render } from "takumi-pdf";

const pdf = await render(document, {
  fonts: await googleFonts(["Noto Sans Devanagari"]),
});

The PDF renderer stops on uncovered characters, because they would be missing from both the page and its text layer. To draw them as blanks or as the font's placeholder glyph instead, set uncoveredText.

A PDF cannot draw filter: blur(2px)

Remove the filter, or rasterize that subtree yourself and place it as an <img>.

PDF has no blur operator, so filter: blur() and drop-shadow() cannot be drawn. The renderer stops rather than ship a page that differs from the image output.

An error occurred while decoding the image data

In PDF output, re-encode the image as PNG, JPEG, or WebP. The message may start with Image could not be decoded.

A PDF embeds those three formats as they are. Other formats, such as GIF, need decoding, and the PDF build decodes only PNG. An image under a CSS filter needs its pixels too, so a JPEG or WebP under a filter raises this error.

Invalid viewport dimensions: a canvas holds 1 to 64 megapixels

Shrink the viewport. 8192 × 8192 is the largest square that fits.

A zero-sized viewport raises the same error. To go larger, render in tiles and stitch them. See Render large canvases.

The content spans more than 20000 pages

Give the tree a height that resolves. A percentage height in a paged render has nothing to resolve against, so the content grows until the page limit stops it.

Node.js

TypeError: fetch failed

Pass the image as a base64 data URL, which skips the fetch.

Node.js's fetch, through undici, can drop the socket while loading a remote img URL (#349).

Layout

The layout is not what I expected

Set drawDebugBorder to outline every node:

Outline every node
import { ImageResponse } from "takumi-js/response";

export function GET() {
  return new ImageResponse(<div tw="flex w-full h-full p-8">Hello</div>, {
    width: 1200,
    height: 630,
    drawDebugBorder: true,
  });
}

If the outlines look right and the render still does not, file an issue.

Last updated on