{"record":{"id":"451370b599b6aad6","repo":"denoland/deno","slug":"failed-to-deserialize-npm-process-state-n","errorCode":null,"errorMessage":"failed to deserialize npm process state: {}\\n{}","messagePattern":"failed to deserialize npm process state: (.+?)\\\\n(.+?)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"libs/npm_installer/process_state.rs","lineNumber":153,"sourceCode":"    // seek to beginning. after the file is written the position will be inherited by this subprocess,\n    // and also this file might have been read before\n    file.seek(std::io::SeekFrom::Start(0))?;\n    file.read_to_end(&mut buf).map_err(|err| {\n      std::io::Error::new(\n        err.kind(),\n        format!(\n          \"failed to reading from {}: {}\",\n          match fd_or_path {\n            FdOrPath::Fd(fd) => format!(\"fd {}\", fd),\n            FdOrPath::Path(path) => path.display().to_string(),\n          },\n          err,\n        ),\n      )\n    })?;\n    let state: NpmProcessState =\n      serde_json::from_slice(&buf).map_err(|err| {\n        std::io::Error::new(\n          ErrorKind::InvalidData,\n          format!(\n            \"failed to deserialize npm process state: {}\\n{}\",\n            err,\n            String::from_utf8_lossy(&buf)\n          ),\n        )\n      })?;\n    Ok(state)\n  }\n\n  pub fn as_serialized(&self) -> String {\n    serde_json::to_string(self).unwrap()\n  }\n}\n","sourceCodeStart":135,"sourceCodeEnd":169,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/libs/npm_installer/process_state.rs#L135-L169","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"# before\nexport DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD=/tmp/state.json   # not deno's state file\ndeno run main.ts   # failed to deserialize npm process state: expected value at line 1 column 1\n\n# after\nunset DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD\ndeno run main.ts","handlingStrategy":"validation","validationCode":"// if you must inspect a state file before handing it to deno, parse it first\nfn looks_like_npm_process_state(bytes: &[u8]) -> bool {\n  let v: serde_json::Value = match serde_json::from_slice(bytes) {\n    Ok(v) => v,\n    Err(_) => return false,\n  };\n  v.get(\"kind\").is_some()\n}","typeGuard":null,"tryCatchPattern":"match NpmProcessState::from_env_var(sys, env_value) {\n  Ok(state) => { /* use state */ }\n  Err(err) if err.kind() == std::io::ErrorKind::InvalidData\n    && err.to_string().contains(\"deserialize npm process state\") =>\n  {\n    // the env var points at a file that is not deno's state JSON — unset it and\n    // let this process resolve npm deps on its own\n    sys.env_remove_var(\"DENO_DONT_USE_INTERNAL_NODE_COMPAT_STATE_FD\");\n  }\n  Err(err) => return Err(err),\n}","preventionTips":["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."],"tags":["npm","process-state","json","deserialization","env-var","deno"],"backgroundTag":"json-deserialization-failed","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}