denoland/deno · error · std::io::Error
failed to deserialize npm process state: {}\n{}
Error message
failed to deserialize npm process state: {}\n{} What it means
After reading the npm process state stream, it is parsed with serde_json::from_slice into NpmProcessState { kind, local_node_modules_path, linker_mode }. A parse failure is wrapped as InvalidData with the serde error plus the full lossy-UTF-8 contents of the buffer, so you can see exactly what bytes were read. It fires when the bytes are not the expected JSON — a foreign file, a truncated state file, or a format written by a different deno version.
Source
Thrown at libs/npm_installer/process_state.rs:153
// seek to beginning. after the file is written the position will be inherited by this subprocess,
// and also this file might have been read before
file.seek(std::io::SeekFrom::Start(0))?;
file.read_to_end(&mut buf).map_err(|err| {
std::io::Error::new(
err.kind(),
format!(
"failed to reading from {}: {}",
match fd_or_path {
FdOrPath::Fd(fd) => format!("fd {}", fd),
FdOrPath::Path(path) => path.display().to_string(),
},
err,
),
)
})?;
let state: NpmProcessState =
serde_json::from_slice(&buf).map_err(|err| {
std::io::Error::new(
ErrorKind::InvalidData,
format!(
"failed to deserialize npm process state: {}\n{}",
err,
String::from_utf8_lossy(&buf)
),
)
})?;
Ok(state)
}
pub fn as_serialized(&self) -> String {
serde_json::to_string(self).unwrap()
}
}
View on GitHub (pinned to 9ad36f7a2c)
Solutions
- Unset DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD and let deno manage it — manual values are the top cause.
- Make the spawning parent and the spawned child use the same deno version so the serialized schema matches.
- If you produce the state file yourself, validate it is the exact JSON text deno wrote (the error prints the offending bytes) and that nothing rewrote it.
Example fix
# before export DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD=/tmp/state.json # not deno's state file deno run main.ts # failed to deserialize npm process state: expected value at line 1 column 1 # after unset DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD deno run main.ts
Defensive patterns
Strategy: validation
Validate before calling
// if you must inspect a state file before handing it to deno, parse it first
fn looks_like_npm_process_state(bytes: &[u8]) -> bool {
let v: serde_json::Value = match serde_json::from_slice(bytes) {
Ok(v) => v,
Err(_) => return false,
};
v.get("kind").is_some()
} Try / catch
match NpmProcessState::from_env_var(sys, env_value) {
Ok(state) => { /* use state */ }
Err(err) if err.kind() == std::io::ErrorKind::InvalidData
&& err.to_string().contains("deserialize npm process state") =>
{
// the env var points at a file that is not deno's state JSON — unset it and
// let this process resolve npm deps on its own
sys.env_remove_var("DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD");
}
Err(err) => return Err(err),
} Prevention
- Scrub DENO_* internal variables when wrapping deno in supervisors (PM2, nodemon, shell wrappers) so children never inherit stale state files.
- Pin parent and child deno to the same version in CI so the serialized state schema always matches.
- If you serialize state yourself, round-trip it through serde_json against the current NpmProcessState type in a test.
When it happens
Trigger: DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD pointing at a file that is not a serialized NpmProcessState; the state file truncated mid-write; a parent deno of one version serializing state that a child of another version cannot parse (added/renamed fields like linker_mode).
Common situations: The env var exported manually or left over in CI pointing at an arbitrary file; deno upgraded on one side of a spawn (e.g. npx-installed deno child vs local parent); state file written to a tmp dir that a cleaner truncated; wrappers re-serializing or appending to the file.
Related errors
- failed to reading from {}: {}
- Invalid port: ''
- refusing to materialize package into symlinked directory
- tar entry '{}' has invalid offset/size (offset={}, size={})
- tar entry '{}' extends beyond archive (offset={}, size={}, a
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/451370b599b6aad6.
Report an issue: GitHub.