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

  1. Set stderr: "piped" in the Deno.Command options before calling spawn()
  2. Use await cmd.output() when you only need the final stderr string, since it defaults to "piped"
  3. 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

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


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/ce63c23b3af8cb07. Report an issue: GitHub.