alyssaxuu/screenity · error · Error
write-after-finalize
write-after-finalize
Error message
Cannot write during finalization
What it means
write() refuses chunks once the uploader has entered finalization (isFinalizing true). Any bytes arriving after finalize begins cannot be delivered, so the chunk size is recorded in bytesLostAfterFinalize, an uploader error is set, and the chunk is rejected.
Source
Thrown at src/pages/CloudRecorder/bunnyTusUploader.js:1270
}),
}).catch((err) =>
this.debugLog("save-upload-meta failed (non-blocking)", { error: String(err) }),
);
} else {
this.debugLog("Skipping save-upload-meta because user token is missing", {
mediaId: this.mediaId,
uploadUrl: this.uploadUrl,
signature: this.signature,
expires: this.expires,
});
}
}
async write(chunk) {
if (this.isFinalizing) {
this.bytesLostAfterFinalize += chunk?.size || 0;
this.setUploaderError("write-after-finalize");
throw new Error("Cannot write during finalization");
}
if (this.isPaused) throw new Error("Uploader paused");
if (!this.uploadUrl) throw new Error("Uploader not initialized");
if (this.status === "error") {
throw new Error(`Uploader in error state: ${this.error}`);
}
await this.checkAuthExpiration();
this.status = "uploading";
if (!this.hasEmittedClientStarted) {
this.hasEmittedClientStarted = true;
this.emitTelemetry("upload_client_started");
}
for (let i = 0; i < chunk.size; i += this.CHUNK_SIZE) {
const subChunk = chunk.slice(i, i + this.CHUNK_SIZE);
this.chunkQueue.push(subChunk);View on GitHub (pinned to 512606387b)
Solutions
- Stop the media recorder and wait for its final dataavailable event BEFORE calling finalize
- Queue chunks and drain the queue before starting finalization (set isFinalizing only after the queue is empty)
- Check uploader.isFinalizing in the write path and drop/flush chunks gracefully instead of crashing callers
- Inspect bytesLostAfterFinalize to quantify how much data was dropped and adjust the stop sequence
Example fix
// before await uploader.finalize(); recorder.stop(); // chunks still arrive after finalize // after recorder.stop(); await once(recorder, "stop"); // flush all remaining chunks await uploader.finalize();
Defensive patterns
Strategy: try-catch
Validate before calling
if (uploader.isFinalizing) {
lostBytes += chunk.size; // park or drop before calling write
} Try / catch
try {
await uploader.write(chunk);
} catch (e) {
if (String(e.message).includes("Cannot write during finalization")) {
// stop feeding; finalize is already in progress
recorderStreamClose();
}
} Prevention
- Always stop the recorder and await its final flush before finalize
- Drain queued chunks before setting isFinalizing
- Track bytesLostAfterFinalize to validate the stop sequence
- Avoid double-stop paths that trigger finalize early
When it happens
Trigger: Calling uploader.write(chunk) after finalize()/stop was invoked, typically from a recording callback that is still delivering MediaRecorder/webcodecs data while the stop path is running.
Common situations: Race between the recorder's last dataavailable event and the stop/finalize flow; user stops the recording while a burst of chunks is queued; double-stop wiring firing finalize before the final flush.
Related errors
- Uploader has already been initialized
- Uploader paused
- Uploader in error state: ${this.error}
- resume-offset-unverified
- Failed to start TUS upload session
AI-assisted analysis of alyssaxuu/screenity@512606387b (2026-09-02).
Data as JSON: /api/errors/ababfd620588c946.
Report an issue: GitHub.