Takumi

Troubleshooting

Every error Takumi prints, what to do about it, and why it happens.

Each heading below is the text an error prints. Search this page for the line your build or your server printed.

Pick the right entry

Most build failures are a target reading the wrong entry. Start here.

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

The default entry reads the export conditions your bundler sets. It covers every server runtime with no configuration.

Bundler errors

Export default doesn't exist in target module

Load the binary yourself:

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

await init({ module_or_path: wasmUrl });

takumi-js takes the same pair: takumi-js/wasm/no-init and takumi-js/wasm-url.

Your browser bundle resolved the Vite entry. Vite, webpack, and Turbopack set the same conditions for a browser build, and that entry loads the binary through a ?url import only Vite reads.

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 is 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 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. Two things cause that.

Hoist the native package

A package manager with a virtual store, such as pnpm or Yarn, has to be told to hoist the native binary. Re-run pnpm i after the change.

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

With pnpm older than 10.5.0, put the equivalent 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 running the install, so installing on macOS and deploying to Linux leaves the target's 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, drop the rule that asks for this:

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 asks the bundler to instantiate the binary, which sends it looking for wasm-bindgen glue the package does not ship: the glue is compiled into dist, and pkg holds the binary alone.

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"] });

esbuild, Rollup, and Bun's bundler flatten the Node entry into one file and leave its new URL(specifier, import.meta.url) call alone, so the path lands next to the output instead of inside node_modules. Vite, webpack, and Turbopack rewrite that call and copy the binary, so they need nothing.

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, and the entry searches the usual layouts for it. External skips the search entirely. If your framework has to bundle it, open an issue with the output layout.

Render errors

No registered font covers क (U+0915)

Register a font covering the characters the error names:

import { googleFonts } from "@takumi-rs/helpers";
import { render } from "takumi-pdf";

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

Those characters would draw nothing and leave nothing in the text layer, so the render stops rather than shipping a page with holes.

A PDF cannot draw filter: blur(2px)

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

PDF has no blur operator, so blur() and drop-shadow() cannot be drawn. Dropping them quietly would ship a page that disagrees with the image output.

An error occurred while decoding the image data

Re-encode the image as PNG, JPEG, or WebP.

Those three embed directly. GIF has no decoder in this build. A CSS filter needs pixels to work on and only PNG decodes for that path, so an image under a filter raises this too when it arrived as JPEG or WebP.

The content spans more than 20000 pages

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

Node.js

TypeError: fetch failed

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

Node'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:

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

export function GET() {
  return new ImageResponse(<></>, {
    width: 100,
    height: 100,
    drawDebugBorder: true,
  });
}

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

Last updated on

On this page