{"record":{"id":"185578e3c9499f3d","repo":"denoland/deno","slug":"cannot-get-stdout-stdout-is-not-piped","errorCode":null,"errorMessage":"Cannot get 'stdout': 'stdout' is not piped","messagePattern":"Cannot get 'stdout': 'stdout' is not piped","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/process/40_process.js","lineNumber":458,"sourceCode":"  [_stderrRid];\n\n  #pid;\n  get pid() {\n    return this.#pid;\n  }\n\n  #stdin = null;\n  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,","sourceCodeStart":440,"sourceCodeEnd":476,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/process/40_process.js#L440-L476","documentation":"Deno's ChildProcess only creates a .stdout ReadableStream when the Command was spawned with stdout: \"piped\". The private #stdout field stays null for \"inherit\", \"null\", or other stdio settings, and the getter throws a TypeError instead of returning null. Note that spawn() defaults stdout to \"inherit\", unlike output() which defaults to \"piped\".","triggerScenarios":"Accessing child.stdout on a ChildProcess from new Deno.Command(cmd, opts).spawn() when opts.stdout is omitted (defaults to \"inherit\") or set to \"inherit\"/\"null\". For example: const child = new Deno.Command(\"echo\", { args: [\"hi\"] }).spawn(); child.stdout;","commonSituations":"Porting code from the removed Deno.run() API; assuming spawn() defaults match output() defaults; helper functions that unconditionally read child.stdout regardless of how the caller configured stdio.","solutions":["Set stdout: \"piped\" in the Deno.Command options before calling spawn()","If you only need the finished output, skip spawn() and use await cmd.output() instead, which defaults stdout/stderr to \"piped\"","Guard access: only touch child.stdout when the options you passed had stdout: \"piped\""],"exampleFix":"// before\nconst child = new Deno.Command(\"echo\", { args: [\"hi\"] }).spawn();\nconst body = child.stdout; // TypeError: 'stdout' is not piped\n\n// after\nconst child = new Deno.Command(\"echo\", { args: [\"hi\"], stdout: \"piped\" }).spawn();\nconst body = child.stdout;","handlingStrategy":"validation","validationCode":"const opts = { stdout: \"piped\", ...rest }; // ensure piped before spawn\nconst wantsStdout = opts.stdout === \"piped\";\nconst child = new Deno.Command(cmd, opts).spawn();\nif (wantsStdout) { const reader = child.stdout.getReader(); }","typeGuard":"function isStdoutPiped(options: Deno.CommandOptions): boolean {\n  return options?.stdout === \"piped\";\n}","tryCatchPattern":"try { stream = child.stdout; } catch (err) { if (err instanceof TypeError && err.message.includes(\"not piped\")) { /* skip capture */ } else throw err; }","preventionTips":["Always set stdio options explicitly instead of relying on spawn()'s inherit defaults","Centralize Command construction in one helper so piped-ness is decided in one place","Remember: spawn() defaults stdio to inherit; output()/outputSync() default to piped"],"tags":["deno","child-process","stdout","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"}