denoland/deno · error · TypeError
Cannot get 'stderr': 'stderr' is not piped
Error message
Cannot get 'stderr': 'stderr' is not piped
What it means
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".
Source
Thrown at ext/process/40_process.js:466
get stdin() {
if (this.#stdin == null) {
throw new TypeError("Cannot get 'stdin': 'stdin' is not piped");
}
return this.#stdin;
}
#stdout = null;
get stdout() {
if (this.#stdout == null) {
throw new TypeError("Cannot get 'stdout': 'stdout' is not piped");
}
return this.#stdout;
}
#stderr = null;
get stderr() {
if (this.#stderr == null) {
throw new TypeError("Cannot get 'stderr': 'stderr' is not piped");
}
return this.#stderr;
}
constructor(key = null, {
signal,
rid,
pid,
stdinRid,
stdoutRid,
stderrRid,
ipcPipeRid, // internal
extraPipeRids,
} = null) {
if (key !== illegalConstructorKey) {
throw new TypeError("Illegal constructor");
}
View on GitHub (pinned to 9ad36f7a2c)
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
Example fix
// before
const child = new Deno.Command("deno", { args: ["eval", "console.error('x')"] }).spawn();
const err = child.stderr; // TypeError: 'stderr' is not piped
// after
const child = new Deno.Command("deno", { args: ["eval", "console.error('x')"], stderr: "piped" }).spawn();
const err = child.stderr; Defensive patterns
Strategy: validation
Validate before calling
const opts = { stderr: "piped", ...rest };
const child = new Deno.Command(cmd, opts).spawn();
if (opts.stderr === "piped") { const errReader = child.stderr.getReader(); } Type guard
function isStderrPiped(options: Deno.CommandOptions): boolean {
return options?.stderr === "piped";
} Try / catch
try { stream = child.stderr; } catch (err) { if (err instanceof TypeError && err.message.includes("not piped")) { /* stderr inherited; nothing to read */ } else throw err; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Cannot get 'stdout': 'stdout' is not piped
- Illegal constructor
- Cannot collect output: 'stderr' is locked
- Piped stdin is not supported for this function, use 'Deno.Co
- ERR_INVALID_ARG_VALUE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/ce63c23b3af8cb07.
Report an issue: GitHub.