{"record":{"id":"e06136a16a9139ce","repo":"denoland/deno","slug":"cannot-collect-output-stdout-is-locked","errorCode":null,"errorMessage":"Cannot collect output: 'stdout' is locked","messagePattern":"Cannot collect output: 'stdout' is locked","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/process/40_process.js","lineNumber":535,"sourceCode":"    };\n    signal?.[abortSignal.add](onAbort);\n    const waitPromise = op_spawn_wait(this.#rid);\n    this.#waitPromise = waitPromise;\n    this.#status = PromisePrototypeThen(waitPromise, (res) => {\n      signal?.[abortSignal.remove](onAbort);\n      this.#waitComplete = true;\n      return res;\n    });\n  }\n\n  #status;\n  get status() {\n    return this.#status;\n  }\n\n  async output() {\n    if (this.#stdout?.locked) {\n      throw new TypeError(\n        \"Cannot collect output: 'stdout' is locked\",\n      );\n    }\n    if (this.#stderr?.locked) {\n      throw new TypeError(\n        \"Cannot collect output: 'stderr' is locked\",\n      );\n    }\n\n    const { 0: status, 1: stdout, 2: stderr } = await SafePromiseAll([\n      this.#status,\n      collectOutput(this.#stdout),\n      collectOutput(this.#stderr),\n    ]);\n\n    return {\n      success: status.success,\n      code: status.code,","sourceCodeStart":517,"sourceCodeEnd":553,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/process/40_process.js#L517-L553","documentation":"ChildProcess.output() internally calls collectOutput() on child.stdout, which needs to acquire a reader on the stream. If you already called getReader(), pipeTo(), or pipedThrough() on child.stdout, the stream is locked and output() throws a TypeError before doing anything. You must choose either manual streaming reads or output(), not both.","triggerScenarios":"Calling const reader = child.stdout.getReader() (or child.stdout.pipeTo(w)) and then awaiting child.output(); also calling child.output() twice after the first call locked/consumed the stream via a prior manual read.","commonSituations":"Starting to stream logs incrementally, then deciding to also await the combined output; helper functions that attach readers for progress display while the main path calls output(); calling output() as a fallback after a partial pipe fails.","solutions":["Pick one strategy: either await child.output() alone, or read child.stdout yourself and collect chunks manually","If a reader was acquired by mistake, call reader.cancel() / releaseLock() on the existing reader before calling output() — but note partial data already consumed is lost","Restructure: pipe stdout yourself if you need incremental processing, then assemble the final Uint8Array from the chunks you collected"],"exampleFix":"// before\nconst child = cmd.spawn();\nconst reader = child.stdout.getReader();\nconst out = await child.output(); // TypeError: 'stdout' is locked\n\n// after\nconst child = cmd.spawn();\nconst out = await child.output();\nconst text = new TextDecoder().decode(out.stdout);","handlingStrategy":"type-guard","validationCode":"function canCollectOutput(child: Deno.ChildProcess): boolean {\n  return !(child.stdout?.locked ?? false) && !(child.stderr?.locked ?? false);\n}\n// call before: if (canCollectOutput(child)) await child.output();","typeGuard":"const outputSafe = (child: Deno.ChildProcess): boolean =>\n  child.stdout?.locked !== true && child.stderr?.locked !== true;","tryCatchPattern":"try { out = await child.output(); } catch (err) { if (err instanceof TypeError && err.message.includes(\"is locked\")) { /* fall back to manual reader loop */ } else throw err; }","preventionTips":["Pick one consumption model per child: manual streaming or output(), never both","Document at the call site that a reader has been attached, so later output() calls are obviously wrong","If you must recover, reader.releaseLock() on the outstanding reader before retrying output()"],"tags":["deno","child-process","streams","stdout","locked-stream","output"],"backgroundTag":"readable-stream-locked","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}