crossbind
GitHub
GUIDE · HELP · TROUBLESHOOTING

Troubleshooting

Almost every common failure has a designated fix that does not involve editing generated artifacts. Read the error literally, work out which layer it belongs to - build, link, binding, runtime, hosting - and apply the least invasive fix that layer offers.

Build errors

ENOENT: no such file or directory … /dist/…

A dependency has not been built yet. Build the whole graph (npm install && npm run build) or build that dependency first - a filtered single-package build skips its dependencies.

undefined symbol: <name>

  • A missing dependency. The package providing the symbol is not in dependencies - add it to both cppjs.config.js and package.json.
  • A symbol clash. Two libraries export the same name (classically iconv). Rename one set with a replaceList entry in cppjs.build.js, or drop the duplicate archive with targetSpecs[].specs.ignoreLibName.

cannot find -l<libname>

The dependency built, but produced a different .a name than expected. Check export.libName in that package and confirm the file exists under its dist/.../lib/.

CPU intrinsics that will not compile

Upstream code using __asm__, CPL_CPUID or <immintrin.h> has no wasm equivalent. Gate it behind #ifdef __wasm__ through a replaceList entry:

cppjs.build.js
replaceList: [{
regex: /CPL_CPUID\(1, cpuinfo\);/g,
replacement: '#ifdef __wasm__\ncpuinfo[0]=0;\n#else\nCPL_CPUID(1, cpuinfo);\n#endif',
paths: ['port/cpl_cpu_features.cpp'],
}]

shared-memory is disallowed … not compiled with atomics

A multithreaded link pulled in a Rust archive built without the atomics features - almost always a stale cargo-type prebuilt. Rebuild that package's wasm output (after rustup toolchain install nightly --component rust-src), or update to a version whose mt prebuilt was produced that way.

RuntimeError: index out of bounds during the build

Emscripten itself ran out of memory while linking. Raise it with targetSpecs[].specs.emccFlags: ['-sINITIAL_MEMORY=512MB'].

Binding errors

A function silently returns null or undefined

The C++ broke one of the binding rules. In order of likelihood:

  • Returning unique_ptr instead of shared_ptr.
  • Returning a raw pointer - wrap it, or return by value.
  • Multiple inheritance in the bound class.
  • A template with no explicit instantiation.
  • The definition lives only in the .cpp; the public surface has to be in the header.

Tried to call … but the function is not exposed

The function is not on the public binding surface: an anonymous namespace, a file-scope static, or a declaration and definition that disagree on static/inline.

Runtime errors

MessageCauseFix
crossOriginIsolated is false, SharedArrayBuffer is not definedmultithreaded build, production host not sending the isolation headersadd COOP/COEP - see Threading
OPFS is only available inside a Worker scopemounting /opfs/... from the main threadinitNative({ useWorker: true })
OPFS is disabled. Enable fs.opfs in configfs: { opfs: false } was set explicitlyremove it, or write under /memfs/...
RuntimeError: out of memorythe wasm heap hit its ceilingraise -sINITIAL_MEMORY / -sMAXIMUM_MEMORY, or stream the input instead of holding it all
m.someFunc is undefineda binding rule violation, or a call made before await initNative(...) resolvedcheck the rules first, then the ordering
instance.method is not a functiona worker runtime: construction returned a promiseconst c = await new X(...), and set dts: 'promise'

Memory growth is enabled by default, so an out-of-memory error usually means the design holds too much at once rather than that a limit is set too low.

Calls hang forever with useWorker: true

Either the worker never spawned - check the Network tab for a request to the worker script - or the C++ inside it is in an infinite loop, which the Sources tab on the worker context will show.

Cross-cutting symptoms

  • `wasm streaming compile failed`. Either the host serves .wasm as application/octet-stream instead of application/wasm, or mt and st artifacts got mixed - clean and rebuild after switching runtime.
  • The build succeeds but produces nothing. Look for Skipping target: ... in the log: a functions.isEnabled override or a target.platform filter is excluding everything.
  • Hot reload ignores a `.cpp` change. Restart the dev server, then verify paths.native resolves where you think it does - the plugins add exactly those files to the watcher.

When nothing above matches

  1. Run the doctor script - most "weird" build failures are a missing toolchain (Node, Docker, Android SDK/NDK, Xcode).
  2. Set LOG_LEVEL: 'DEBUG' in ~/.cppjs.json for verbose tracing; it usually names the failing step.
  3. Reduce to the smallest reproducer: a fresh project with only the failing dependency.
  4. Search the error text in the source - error messages are unique enough to find where they are thrown.
  5. File an issue when the error comes from the toolchain itself rather than from your configuration or the upstream library.
Type to search every guide page and section.
↑↓ navigate↵ openesc close