can1357/oh-my-pi · error
InvalidArg
InvalidArg
Error message
error.to_string()
What it means
pi-natives' `utf8` helper copies a JS string into a Rust &str via napi_get_value_string_utf8 using a thread-local scratch arena. After copying, it validates the bytes with str::from_utf8; if Node-API returned bytes that aren't valid UTF-8, it returns a Node-API Error with Status::InvalidArg carrying the UTF-8 validation message. This should be practically unreachable (Node-API guarantees UTF-8 output), so hitting it signals arena/pointer misuse or a corrupt napi buffer rather than bad JS input.
Source
Thrown at crates/pi-natives/src/js.rs:234
pub fn utf8(value: JsString<'_>) -> Result<Utf8> {
let raw = value.value();
ARENA.with(|arena| {
let (start, avail) = arena.tail(1);
if avail >= 2 {
// SAFETY: `start..start + avail` is past every committed range.
let ptr = unsafe { arena.base().add(start) };
let mut written = 0;
// SAFETY: `raw` is a JS string owned by the live callback; Node-API
// writes at most `avail - 1` bytes plus a NUL into the free tail.
let status = unsafe {
sys::napi_get_value_string_utf8(raw.env, raw.value, ptr.cast(), avail, &mut written)
};
napi::check_status!(status, "Failed to read JavaScript string")?;
if written < avail - 1 {
// SAFETY: Node-API initialised `written` bytes at `ptr`.
let bytes = unsafe { slice::from_raw_parts(ptr, written) };
if let Err(error) = str::from_utf8(bytes) {
return Err(Error::new(Status::InvalidArg, error.to_string()));
}
arena.commit(start, written);
return Ok(Utf8(TextRepr::Scratch { ptr: NonNull::new(ptr).unwrap(), len: written }));
}
}
let mut len = 0;
// SAFETY: a null buffer asks Node-API for the byte length only.
let status = unsafe {
sys::napi_get_value_string_utf8(raw.env, raw.value, ptr::null_mut(), 0, &mut len)
};
napi::check_status!(status, "Failed to measure JavaScript string")?;
let mut buf: Vec<u8> = Vec::with_capacity(len + 1);
let mut written = 0;
// SAFETY: `buf` holds the measured length plus the NUL slot.
let status = unsafe {
sys::napi_get_value_string_utf8(
raw.env,View on GitHub (pinned to 9690622007)
Solutions
- Rebuild the native addon from source (`cargo build -p pi-natives` / the package's install script) to eliminate binary/ABI mismatch, then reload the host process.
- Update to the latest pi-natives version — if this fires at all it is a library bug; check the changelog/issues for arena fixes and upgrade.
- Restart the Node/Bun process to reset the thread-local arena; if the error is transient it points at scratch-buffer corruption during a long-lived process.
- If it persists, reduce the input string to a minimal reproduction (length, code points) and file a bug — the InvalidArg is raised on library-internal bytes, not on user input.
Example fix
// before: stale prebuilt addon triggers invalid UTF-8 from the arena fast path
Error [InvalidArg]: invalid utf-8 sequence of 1 bytes from index 12
// after: rebuild the native module to match the current ABI
$ bun run build:natives # or: cargo build --release -p pi-natives
$ node -e "require('./pi-natives')" # restart the host process Defensive patterns
Strategy: try-catch
Validate before calling
function isUsableNativeAddon(mod) {
return typeof mod === 'object' && mod !== null && typeof mod.binding === 'object';
} Try / catch
let result;
try {
result = nativeCallWithString(str);
} catch (err) {
if (err instanceof Error && err.code === 'InvalidArg') {
// Library-internal UTF-8 validation failure: rebuild addon / restart process
console.error('pi-natives returned InvalidArg; rebuild the native addon and retry');
} else {
throw err;
}
} Prevention
- Rebuild pi-natives whenever Rust toolchain, Node, or Bun versions change so the .node binary matches the current ABI.
- Restart long-lived processes periodically if they invoke native bindings heavily, so a scratch-arena bug can't accumulate.
- Keep pi-natives up to date; this error signals a library bug — report minimal reproductions upstream.
When it happens
Trigger: Calling the exposed native binding that takes a JS string argument when the fast-path arena copy yields invalid UTF-8 — e.g. after an arena overflow/miscommit bug, memory corruption, or a mismatched native binary that violates the napi_get_value_string_utf8 contract. Surfaces in JS as an Error with code 'InvalidArg'.
Common situations: A stale or ABI-mismatched pi-natives .node binary (native addon rebuilt against different Rust/Node versions) being loaded; running under a patched or exotic Node-API shim; reproducing after a partial arena commit corrupted the scratch buffer.
Related errors
- failed to initialize AppKit
- Invalid memory glob URL: ${input}
- Memory glob patterns require the ${MEMORY_NAMESPACE} namespa
- Invalid URL encoding in memory:// path: ${input}
- memory:// URL does not contain a glob pattern: ${input}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f88098587d61306c.
Report an issue: GitHub.