{"record":{"id":"b2678b9c7520bdd8","repo":"run-llama/liteparse","slug":"wasi-proc-exit-called-with-code-code","errorCode":null,"errorMessage":"WASI proc_exit called with code ${code}","messagePattern":"WASI proc_exit called with code (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/wasm/scripts/patch-wasi-imports.js","lineNumber":90,"sourceCode":"      const ptr = view.getUint32(iovs + i * 8, true);\n      const len = view.getUint32(iovs + i * 8 + 4, true);\n      // Optionally log stderr to console\n      if (fd === 2 && len > 0) {\n        try {\n          const text = new TextDecoder().decode(mem.subarray(ptr, ptr + len));\n          console.warn(\"[pdfium]\", text);\n        } catch (_) {}\n      }\n      total += len;\n    }\n    view.setUint32(nwritten, total, true);\n    return ${ERRNO_SUCCESS};\n  },\n  path_filestat_get() { return ${ERRNO_NOENT}; },\n  path_open() { return ${ERRNO_NOENT}; },\n  path_remove_directory() { return ${ERRNO_NOSYS}; },\n  path_unlink_file() { return ${ERRNO_NOSYS}; },\n  proc_exit(code) { throw new Error(\"WASI proc_exit called with code \" + code); },\n};\n\nconst __env_stubs = {\n  // __c_longjmp is a WASM exception handling tag used for setjmp/longjmp.\n  // It must be a WebAssembly.Tag, not a function.\n  __c_longjmp: new WebAssembly.Tag({ parameters: [\"i32\"] }),\n};\n// --- end stubs ---\n`;\n\n// 1. Remove the top-level `import ... from \"env\"` and `import ... from \"wasi_snapshot_preview1\"`\n//    These are ES module imports that can't resolve in a browser.\nsource = source.replace(/^import \\* as import\\d+ from \"(?:env|wasi_snapshot_preview1)\";?\\n/gm, \"\");\n\n// 2. Inject stubs before the __wbg_get_imports function\nsource = source.replace(\n  \"function __wbg_get_imports() {\",\n  STUBS_CODE + \"\\nfunction __wbg_get_imports() {\"","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/run-llama/liteparse/blob/22d2dd8cd7f7b9320102b57ddaf0e663ff7d15a8/packages/wasm/scripts/patch-wasi-imports.js#L72-L108","documentation":"During the WASM build, a post-processing script patches the generated wasm-bindgen JS glue to supply stubbed WASI imports, because the bundled PDFium build must run in a sandboxed browser with no filesystem. The stubbed `proc_exit` is not expected to ever be called; if the WASM module attempts to exit the WASI process, the stub throws this Error to surface the unexpected termination loudly instead of silently doing nothing. In practice it means the underlying C/C++ code invoked `exit()` — usually a fatal abort inside PDFium or the parser.","triggerScenarios":"Loading or calling the liteparse WASM module (LiteParse.parse and friends) when the embedded PDFium/native code calls the WASI `proc_exit` syscall, i.e. C-level `exit()` is reached. Typical causes: a fatal internal abort in PDFium while parsing a malformed or encrypted PDF, or code paths requiring preopen filesystem access that the stubs deny leading to an exit path.","commonSituations":"Bundling the .wasm with a PDFium build that calls exit() on unrecoverable input; running in a browser/Node environment where the patched WASI stubs replaced a full WASI runtime like wasmer/wasmoon; parsing corrupted or password-protected PDFs in the WASM target.","solutions":["Inspect the stderr logs emitted as '[pdfium] ...' by the fd_write stub just before the throw to identify the native-side abort message","Verify the PDF input: try the same file via the native CLI (cargo/npm/pip) to confirm whether the document itself triggers the abort","Upgrade to the latest liteparse-wasm package — the pdfium WASM build or patch script may already handle this exit path","If you maintain the build, extend patch-wasi-imports.js stubs (e.g. allowlist needed WASI calls) or embed a WASI runtime instead of stubs","Catch the Error around parse calls and treat the document as unparseable in the WASM target, falling back to a server-side parse"],"exampleFix":"// before\ntry {\n  const result = await parser.parse(fileBytes, 'doc.pdf');\n} catch (e) { /* unhandled: WASI proc_exit called with code 1 */ }\n// after\ntry {\n  const result = await parser.parse(fileBytes, 'doc.pdf');\n} catch (e) {\n  if (String(e).includes('proc_exit')) {\n    result = await parseViaServer(fileBytes); // fallback off the WASM target\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":"// No pre-call validation possible; optionally verify wasm asset version\nconst isWasmBuild = typeof WebAssembly === 'object';\nif (!isWasmBuild) throw new Error('liteparse-wasm requires WebAssembly support');","typeGuard":"function isProcExitError(e: unknown): e is Error {\n  return e instanceof Error && e.message.includes('proc_exit');\n}","tryCatchPattern":"try {\n  result = await parser.parse(bytes, name);\n} catch (e) {\n  if (isProcExitError(e)) {\n    console.error('Native parser aborted (proc_exit); falling back to server parse', e);\n    result = await parseViaServer(bytes);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Validate/sanitize PDF inputs (reject encrypted or known-malformed files) before the WASM parser","Keep liteparse-wasm and its bundled pdfium build up to date","Watch '[pdfium]' console.warn output during development to catch native aborts early","Keep a server-side (native CLI/node binary) parse fallback for documents the WASM target cannot handle"],"tags":["wasm","wasi","browser","pdfium"],"backgroundTag":"unsupported-operation","analyzedSha":"22d2dd8cd7f7b9320102b57ddaf0e663ff7d15a8","analyzedAt":"2026-09-08T06:09:49.009Z","contentChangedAt":"2026-09-08T06:09:49.009Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}