{"record":{"id":"0719c7f518614ca2","repo":"denoland/deno","slug":"datacloneerror-0719c7","errorCode":"DataCloneError","errorMessage":"Cannot transfer a locked ReadableStream","messagePattern":"Cannot transfer a locked ReadableStream","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"error","filePath":"ext/web/06_streams.js","lineNumber":7892,"sourceCode":"  setUpWritableStreamDefaultController(\n    stream,\n    controller,\n    startAlgorithm,\n    writeAlgorithm,\n    closeAlgorithm,\n    abortAlgorithm,\n    1,\n    sizeAlgorithm,\n  );\n}\n\n/**\n * @param value {ReadableStream<any>}\n * @param port {MessagePort}\n */\nfunction readableStreamTransferSteps(value, port) {\n  if (isReadableStreamLocked(value)) {\n    throw new DOMException(\n      \"Cannot transfer a locked ReadableStream\",\n      \"DataCloneError\",\n    );\n  }\n  const writable = new WritableStream(_brand);\n  setUpCrossRealmTransformWritable(writable, port);\n  const promise = readableStreamPipeTo(value, writable, false, false, false);\n  setPromiseIsHandledToTrue(promise);\n}\n\n/**\n * @param port {MessagePort}\n * @returns {ReadableStream<any>}\n */\nfunction readableStreamTransferReceivingSteps(port) {\n  const stream = new ReadableStream(_brand);\n  setUpCrossRealmTransformReadable(stream, port);\n  return stream;","sourceCodeStart":7874,"sourceCodeEnd":7910,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/web/06_streams.js#L7874-L7910","documentation":"DataCloneError DOMException thrown by readableStreamTransferSteps, the structured-clone serializer hook for ReadableStream (ext/web/06_streams.js). Transferring a ReadableStream via postMessage/structuredClone pipes its contents across the MessagePort, which requires taking a reader; if the stream is already locked (active reader, ongoing pipeTo, or tee), the transfer is refused.","triggerScenarios":"postMessage(readableStream, [readableStream]) or structuredClone(rs, { transfer: [rs] }) while a getReader() is outstanding, a pipeTo/pipeThrough is in progress, or the stream was tee'd — all of which hold the lock.","commonSituations":"Sending a fetch response body to a Worker after starting to read it in the main thread; transfer code that forgot releaseLock() on a reader; frameworks that implicitly lock streams (tee for inspection) before user transfer code runs.","solutions":["Release the lock before transferring: reader.releaseLock() (and cancel/finish any pipeTo) so isReadableStreamLocked is false.","Transfer the stream before anything reads it — move it to the Worker first and read there.","If you need the data in both places, tee() first and transfer only the branch you do not consume locally... instead, cancel the local branch after tee and transfer the other."],"exampleFix":"// before\nconst reader = res.body.getReader();\nreader.read();\nworker.postMessage(res.body, [res.body]); // DataCloneError: locked\n\n// after\nconst body = res.body;\nworker.postMessage(body, [body]); // transfer first, unlocked\n// read it inside the worker","handlingStrategy":"validation","validationCode":"// readable.locked mirrors the internal isReadableStreamLocked check.\nif (stream.locked) {\n  // release or cancel before transfer\n  // reader.releaseLock();  await stream.cancel();  or finish pipeTo\n}\nworker.postMessage(stream, [stream]);","typeGuard":null,"tryCatchPattern":"try {\n  worker.postMessage(stream, [stream]);\n} catch (err) {\n  if (err instanceof DOMException && err.name === 'DataCloneError') {\n    throw new Error('ReadableStream still locked; release the reader before transferring');\n  }\n  throw err;\n}","preventionTips":["Transfer streams before reading them; read in the receiving realm.","Always pair getReader() with releaseLock() (or cancel) in a finally block.","Remember pipeTo/pipeThrough and tee() also lock a readable stream."],"tags":["streams","readable-stream","structured-clone","postmessage","transferable"],"backgroundTag":"transfer-locked-stream","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-01T18:04:01.013Z"}