{"record":{"id":"e8206258b17817d3","repo":"denoland/deno","slug":"readablestream-is-already-locked","errorCode":null,"errorMessage":"ReadableStream is already locked","messagePattern":"ReadableStream is already locked","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":6220,"sourceCode":"   */\n  pipeThrough(transform, options = { __proto__: null }) {\n    webidl.assertBranded(this, ReadableStreamPrototype);\n    const prefix = \"Failed to execute 'pipeThrough' on 'ReadableStream'\";\n    webidl.requiredArguments(arguments.length, 1, prefix);\n    transform = webidl.converters.ReadableWritablePair(\n      transform,\n      prefix,\n      \"Argument 1\",\n    );\n    options = webidl.converters.StreamPipeOptions(\n      options,\n      prefix,\n      \"Argument 2\",\n    );\n    const { readable, writable } = transform;\n    const { preventClose, preventAbort, preventCancel, signal } = options;\n    if (isReadableStreamLocked(this)) {\n      throw new TypeError(\"ReadableStream is already locked\");\n    }\n    if (isWritableStreamLocked(writable)) {\n      throw new TypeError(\"Target WritableStream is already locked\");\n    }\n    const promise = readableStreamPipeTo(\n      this,\n      writable,\n      preventClose,\n      preventAbort,\n      preventCancel,\n      signal,\n    );\n    setPromiseIsHandledToTrue(promise);\n    return readable;\n  }\n\n  /**\n   * @param {WritableStream<R>} destination","sourceCodeStart":6202,"sourceCodeEnd":6238,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L6202-L6238","documentation":"ReadableStream.pipeThrough(transform, options) was called while the source stream is locked by an existing reader or an active pipe. pipeThrough must attach a reader to the source internally, so this.locked must be false when it is called.","triggerScenarios":"Calling getReader() (even briefly, for sniffing) and then pipeThrough() without releaseLock(); running two pipes on the same source concurrently; async iteration started before piping.","commonSituations":"Middleware that both reads and pipes; logging the first bytes then piping the rest; attempting fan-out by piping twice instead of using tee().","solutions":["Call reader.releaseLock() before pipeThrough().","For fan-out use const [a, b] = stream.tee() and pipe each branch.","Await the first pipe's completion before starting a second pipeline on the same source."],"exampleFix":"// before\nconst r = stream.getReader();\nawait peek(r);\nstream.pipeThrough(transformer); // TypeError: ReadableStream is already locked\n\n// after\nconst r = stream.getReader();\nawait peek(r);\nr.releaseLock();\nstream.pipeThrough(transformer); // ok","handlingStrategy":"validation","validationCode":"if (readable.locked) {\n  throw new Error('source locked — release its reader before piping');\n}\nreadable.pipeThrough(transformer);","typeGuard":null,"tryCatchPattern":"try {\n  readable.pipeThrough(transformer);\n} catch (e) {\n  if (e instanceof TypeError && e.message === 'ReadableStream is already locked') {\n    reader.releaseLock();\n    readable.pipeThrough(transformer); // retry once unlocked\n  } else throw e;\n}","preventionTips":["Piping acquires the source exclusively; release readers first.","Use tee() for multiple consumers instead of piping twice.","Flag getReader() results that are never releaseLock()ed on paths that also pipe."],"tags":["readable-stream","pipethrough","locked-stream","pipe"],"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-14T00:17:10.932Z"}