schollz/croc · error · Error
Received file data before it was requested
Error message
Received file data before it was requested
What it means
Thrown by DataReceiver.accept when a data chunk arrives while no file receive is active (this.active is undefined). The protocol only streams data after the recipient sends 'recipientready' for a specific file, so unsolicited data means the sender started streaming early, continued after file completion, or sent data for a file the recipient never requested. It fails the receiver loop and aborts the transfer.
Source
Thrown at web/src/protocol/client.ts:614
const bytes = payload.slice(8);
await this.accept(position, bytes);
} catch (error) {
if (this.stopped) return;
this.stopped = true;
this.fail(error instanceof Error ? error : new Error(String(error)));
}
}
}
private fail(error: Error) {
this.failure ??= error;
this.active?.reject(error);
this.active = undefined;
}
private accept(position: number, bytes: Uint8Array) {
const active = this.active;
if (!active) throw new Error("Received file data before it was requested");
active.queue = active.queue.then(async () => {
if (active.received.has(position)) throw new Error("Received a duplicate file chunk");
if (
position < 0 ||
position % CHUNK_SIZE !== 0 ||
bytes.byteLength === 0 ||
bytes.byteLength > CHUNK_SIZE ||
position + bytes.byteLength > active.file.size
) {
throw new Error("Received a file chunk outside the advertised file size");
}
active.received.add(position);
await active.sink.writeAt(position, bytes);
active.bytes += bytes.byteLength;
active.progress(active.bytes);
if (active.bytes === active.file.size) {
this.active = undefined;
active.resolve();View on GitHub (pinned to e25f1bdc04)
Solutions
- Check sender loop ordering: data must only follow a recipientready and stop before close-sender
- When resuming/reconnecting, drain or re-create data sockets so stale frames from the previous session cannot arrive
- Ensure the sender's chunk scheduling across multiple sockets completes before it sends its close message
- Add logging of active-file lifecycle (set at receive(), cleared at completion) to identify which boundary leaks the unsolicited chunk
Defensive patterns
Strategy: try-catch
Try / catch
catch (e) {
if (e instanceof Error && e.message === "Received file data before it was requested") {
// sender streamed outside the protocol window: abort and restart, resuming is unsafe
}
throw e;
} Prevention
- If you implement a sender, only stream data between recipientready and close-sender
- Drain or recreate data sockets on reconnect so stale frames never reach a fresh DataReceiver
- Do not reuse a DataReceiver instance across transfers; construct it per receiveFiles call as the library does
When it happens
Trigger: Sender begins streaming before receiving recipientready; sender sends extra chunks after active.bytes === file.size resolved the promise (this.active reset to undefined); leftover in-flight frames from a previous file arriving after completion; sender and recipient disagree on file count so data for file N+1 arrives before its request.
Common situations: Sender implementation that pipelines the next file without waiting for close-sender/close-recipient; race where the final chunks of a completed file are still queued on a data socket while the recipient starts the next file (the dup-check then fires, but unsolicited-data fires when active is undefined between files); reconnect scenarios where the sender resumes sending immediately.
Related errors
- Unexpected peer message: ${message.t}
- Expected recipient to close the file, got ${closed.t}
- Received a duplicate file chunk
- Expected sender to close the file, got ${close.t}
- Expected transfer completion, got ${finishedMessage.t}
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/11fbc13b4e58e5f0.
Report an issue: GitHub.