{"record":{"id":"ce63c23b3af8cb07","repo":"denoland/deno","slug":"cannot-get-stderr-stderr-is-not-piped","errorCode":null,"errorMessage":"Cannot get 'stderr': 'stderr' is not piped","messagePattern":"Cannot get 'stderr': 'stderr' is not piped","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/process/40_process.js","lineNumber":466,"sourceCode":"  get stdin() {\n    if (this.#stdin == null) {\n      throw new TypeError(\"Cannot get 'stdin': 'stdin' is not piped\");\n    }\n    return this.#stdin;\n  }\n\n  #stdout = null;\n  get stdout() {\n    if (this.#stdout == null) {\n      throw new TypeError(\"Cannot get 'stdout': 'stdout' is not piped\");\n    }\n    return this.#stdout;\n  }\n\n  #stderr = null;\n  get stderr() {\n    if (this.#stderr == null) {\n      throw new TypeError(\"Cannot get 'stderr': 'stderr' is not piped\");\n    }\n    return this.#stderr;\n  }\n\n  constructor(key = null, {\n    signal,\n    rid,\n    pid,\n    stdinRid,\n    stdoutRid,\n    stderrRid,\n    ipcPipeRid, // internal\n    extraPipeRids,\n  } = null) {\n    if (key !== illegalConstructorKey) {\n      throw new TypeError(\"Illegal constructor\");\n    }\n","sourceCodeStart":448,"sourceCodeEnd":484,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/process/40_process.js#L448-L484","documentation":"Deno's ChildProcess only creates a .stderr ReadableStream when the Command was spawned with stderr: \"piped\". The private #stderr field stays null for \"inherit\" or \"null\" stdio, and the getter throws a TypeError rather than returning null. spawn() defaults stderr to \"inherit\", unlike output() which defaults to \"piped\".","triggerScenarios":"Accessing child.stderr on a ChildProcess from new Deno.Command(cmd, opts).spawn() when opts.stderr is omitted or set to \"inherit\"/\"null\", e.g. capturing errors of a process whose stderr was left inherited by the terminal.","commonSituations":"Porting from the removed Deno.run() API; forgetting that spawn() defaults differ from output(); writing generic wrappers that always read .stderr to capture failure output.","solutions":["Set stderr: \"piped\" in the Deno.Command options before calling spawn()","Use await cmd.output() when you only need the final stderr string, since it defaults to \"piped\"","Only access .stderr when the spawn options requested piped stderr"],"exampleFix":"// before\nconst child = new Deno.Command(\"deno\", { args: [\"eval\", \"console.error('x')\"] }).spawn();\nconst err = child.stderr; // TypeError: 'stderr' is not piped\n\n// after\nconst child = new Deno.Command(\"deno\", { args: [\"eval\", \"console.error('x')\"], stderr: \"piped\" }).spawn();\nconst err = child.stderr;","handlingStrategy":"validation","validationCode":"const opts = { stderr: \"piped\", ...rest };\nconst child = new Deno.Command(cmd, opts).spawn();\nif (opts.stderr === \"piped\") { const errReader = child.stderr.getReader(); }","typeGuard":"function isStderrPiped(options: Deno.CommandOptions): boolean {\n  return options?.stderr === \"piped\";\n}","tryCatchPattern":"try { stream = child.stderr; } catch (err) { if (err instanceof TypeError && err.message.includes(\"not piped\")) { /* stderr inherited; nothing to read */ } else throw err; }","preventionTips":["Decide upfront whether errors must be captured (piped) or shown live (inherit)","Write wrappers that read .stderr only when the corresponding option was piped","Keep stdio option literals next to the code that consumes the streams"],"tags":["deno","child-process","stderr","stdio","spawn"],"backgroundTag":"stdio-not-piped","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}