# Fix TransformStream default writer already released

## TL;DR

Never write to a writer after calling `releaseLock()` - either finish all writes first or re-acquire with `getWriter()` after closing. The usual bug is calling `getWriter()` twice on one stream or writing after `releaseLock()`. Find the double-acquire, await `writer.close()` before any second acquire, and keep exactly one live writer per stream.

## Verbatim error

```text
workerd TypeError: TransformStream default writer already released
```

## Steps

1. Find every acquire and release: run `grep -rn "getWriter" src/` and `grep -rn "releaseLock" src/`. Expected: a short list of call sites, usually two acquires on the same stream or a write after a release.
2. Restructure so only one writer exists at a time: do all writes, then `await writer.close()`, and only then call `getWriter()` again if you truly need another. Expected: no second `getWriter()` while a writer is open.
3. Move `releaseLock()` to after the final write and the `await writer.close()`. Expected: writes complete before the lock is released.
4. If you use `tee()`, write only through the two branch streams and never touch the original stream's writer again. Expected: all writes go to branch writers.
5. Redeploy and exercise the streaming path while watching `wrangler tail`. Expected: the stream completes with no TypeError.

## Use this when

- A Worker throws "TransformStream default writer already released"
- Custom TransformStream code proxies or transforms streaming responses
- The error appears after adding a second writer or a `releaseLock()` call

## Not for this skill when

- The error is about a ReadableStream reader being released (mirror issue, different fix)
- You see "Response body already used" (single-use body problem)
- `pipeTo` aborts with an AbortError (abort handling, not writer lifecycle)

## Variant phrasings

- Cannot write to a released writer TransformStream
- getWriter called twice on transform stream
- workerd transform stream writer lock released
- TypeError: writer has been released

## Why it happens

A stream has a single default writer lock. `releaseLock()` frees the lock but leaves the writer object dead - any later `write()` on it throws. Calling `getWriter()` a second time while the first writer still holds the lock throws the same error. Both are lifecycle bugs, not runtime bugs.

## Edge cases

- Aborting via an AbortController can release the writer implicitly; guard writes after aborts.
- `tee()` closes branches independently - closing one branch does not close the other.
- Middleware that also acquires a writer on a stream you pass through will collide with your writer; pass the readable side onward instead.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_7US5gjRPQ6z19sqNwS8Eyw
