denoland/deno · error · TypeError

A writable stream is not associated with the writer

Error message

A writable stream is not associated with the writer

What it means

TypeError thrown by the WritableStreamDefaultWriter.desiredSize getter when this[_stream] is undefined (ext/web/06_streams.js). A writer only references its stream while it holds the lock; after releaseLock() (or after the stream errors/finalizes and the association is dropped), desiredSize can no longer be computed and the getter throws.

Source

Thrown at ext/web/06_streams.js:7529

    this[_brand] = _brand;
    setUpWritableStreamDefaultWriter(this, stream);
  }

  /** @returns {Promise<void>} */
  get closed() {
    try {
      webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
    } catch (err) {
      return PromiseReject(err);
    }
    return this[_closedPromise].promise;
  }

  /** @returns {number} */
  get desiredSize() {
    webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
    if (this[_stream] === undefined) {
      throw new TypeError(
        "A writable stream is not associated with the writer",
      );
    }
    return writableStreamDefaultWriterGetDesiredSize(this);
  }

  /** @returns {Promise<void>} */
  get ready() {
    try {
      webidl.assertBranded(this, WritableStreamDefaultWriterPrototype);
    } catch (err) {
      return PromiseReject(err);
    }
    return this[_readyPromise].promise;
  }

  /**
   * @param {any} reason

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Read desiredSize before calling releaseLock(), while the writer still holds the lock.
  2. After releasing, call stream.getWriter() again to get a valid writer before querying desiredSize.
  3. Track the released state in your own variable and skip desiredSize queries once released.
  4. Wrap the access in try/catch TypeError when the lock state cannot be proven.

Example fix

// before
const writer = ws.getWriter();
writer.releaseLock();
console.log(writer.desiredSize); // TypeError: no stream associated

// after
const writer = ws.getWriter();
const size = writer.desiredSize; // read while locked
writer.releaseLock();
Defensive patterns

Strategy: try-catch

Validate before calling

// Track the lock yourself: after releaseLock() the writer is inert.
let released = false;
function desiredSizeOrZero(writer) {
  if (released) return 0; // or null per your backpressure convention
  return writer.desiredSize;
}
// ... on cleanup: released = true; writer.releaseLock();

Try / catch

let size;
try {
  size = writer.desiredSize;
} catch (err) {
  if (err instanceof TypeError && /not associated with the writer/.test(err.message)) size = null;
  else throw err;
}

Prevention

When it happens

Trigger: writer.releaseLock() followed by reading writer.desiredSize; inspecting desiredSize after the stream was aborted/errored far enough to detach the writer; storing a writer past its lock lifetime and polling its desiredSize.

Common situations: Backpressure checks in cleanup/monitoring code that run after releaseLock; loops that release the lock on error and then log desiredSize for diagnostics; using one writer object after re-acquiring with getWriter() on the same stream.

Related errors


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