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.
| Target | Import |
|---|---|
| Node.js, Bun, Deno, Cloudflare Workers | takumi-js / takumi-pdf |
| A Next.js route, either runtime | takumi-js / takumi-pdf/next |
| A browser bundle, image output | takumi-js/wasm/no-init plus takumi-js/wasm-url |
| A browser or web worker bundle, PDF | takumi-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.
import init, { render } from "takumi-pdf/no-init";
import wasmUrl from "takumi-pdf/wasm-url";
await init({ module_or_path: wasmUrl });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:
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.
publicHoistPattern:
- "@takumi-rs/core-*"With pnpm older than 10.5.0, put the setting in .npmrc instead:
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| Target | Package |
|---|---|
| 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:
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@latestThe 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@latestRspack 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.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:
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:
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:
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