{"record":{"id":"3ab9abeaa8ff6cc4","repo":"denoland/deno","slug":"the-stream-is-already-locked","errorCode":null,"errorMessage":"The stream is already locked","messagePattern":"The stream is already locked","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":4790,"sourceCode":"    stream,\n    controller,\n    startAlgorithm,\n    writeAlgorithm,\n    closeAlgorithm,\n    abortAlgorithm,\n    highWaterMark,\n    sizeAlgorithm,\n  );\n}\n\n/**\n * @template W\n * @param {WritableStreamDefaultWriter<W>} writer\n * @param {WritableStream<W>} stream\n */\nfunction setUpWritableStreamDefaultWriter(writer, stream) {\n  if (isWritableStreamLocked(stream) === true) {\n    throw new TypeError(\"The stream is already locked\");\n  }\n  writer[_stream] = stream;\n  stream[_writer] = writer;\n  const state = stream[_state];\n  if (state === \"writable\") {\n    if (\n      writableStreamCloseQueuedOrInFlight(stream) === false &&\n      stream[_backpressure] === true\n    ) {\n      writer[_readyPromise] = new Deferred();\n    } else {\n      writer[_readyPromise] = new Deferred();\n      writer[_readyPromise].resolve(undefined);\n    }\n    writer[_closedPromise] = new Deferred();\n  } else if (state === \"erroring\") {\n    writer[_readyPromise] = new Deferred();\n    writer[_readyPromise].reject(stream[_storedError]);","sourceCodeStart":4772,"sourceCodeEnd":4808,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L4772-L4808","documentation":"WritableStreamDefaultWriter (stream.getWriter() or new WritableStreamDefaultWriter(stream)) was acquired while the writable was already locked. A WritableStream supports one writer or one active pipe at a time; isWritableStreamLocked(stream) === true triggers this TypeError.","triggerScenarios":"Two getWriter() calls without an intervening releaseLock(); pipeTo() still writing while code calls getWriter(); a writer abandoned after abort()/close() without releaseLock(); wrappers that internally getWriter() on a stream the caller also writes to.","commonSituations":"Shared WritableStreams (logs, response sinks) written by several producers; helpers that pre-write a header via getWriter() before handing off; retry logic re-acquiring a writer per attempt.","solutions":["Call writer.releaseLock() when done — including in finally blocks after errors.","Keep a single long-lived writer per stream instead of acquiring one per write.","Await pipeTo() completion before acquiring a writer; abort the pipe first if you must preempt.","Route concurrent producers through one queue owned by a single writer."],"exampleFix":"// before\nconst w1 = ws.getWriter();\nawait w1.write('a');\nconst w2 = ws.getWriter(); // TypeError: The stream is already locked\n\n// after\nconst w1 = ws.getWriter();\nawait w1.write('a');\nw1.releaseLock();\nconst w2 = ws.getWriter(); // ok","handlingStrategy":"validation","validationCode":"if (ws.locked) {\n  throw new Error('writable is locked — release the writer or await the pipe');\n}\nconst writer = ws.getWriter();","typeGuard":null,"tryCatchPattern":"try {\n  writer = ws.getWriter();\n} catch (e) {\n  if (e instanceof TypeError && e.message === 'The stream is already locked') {\n    previousWriter.releaseLock(); // then retry once\n    writer = ws.getWriter();\n  } else throw e;\n}","preventionTips":["One writer per stream; call releaseLock() in finally, including after abort()/close().","Await the writer's close()/abort() before creating another.","Pass writers, not writables, across API boundaries to encode ownership."],"tags":["writable-stream","locked-stream","writer"],"backgroundTag":"writable-stream-locked","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}