schollz/croc · error · Error

Received a duplicate file chunk

Error message

Received a duplicate file chunk

What it means

Thrown inside DataReceiver's per-chunk queue when the same chunk position is delivered twice for the active file. Each position is recorded in active.received on first acceptance, so a repeat means the sender retransmitted a chunk or a data socket duplicated a frame. Because chunk ranges must tile the file exactly once, duplicates abort the transfer rather than being silently ignored.

Source

Thrown at web/src/protocol/client.ts:616

      } 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();
      } else if (active.bytes > active.file.size) {
        throw new Error("Received more data than the advertised file size");

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Verify both peers open the same number of data connections (relay banner ports) so chunk stride partitioning matches
  2. If implementing resume, ensure the receiver's received-set and the sender's ranges restart coherently — do not reuse a live DataReceiver across sessions
  3. Disable or dedupe sender-side retry logic on the data sockets (reliability belongs to the relay/TCP layer)
  4. Capture the duplicated position value in logs to see whether it is the same index across failures (stride bug) or random (network duplication)
Defensive patterns

Strategy: try-catch

Try / catch

catch (e) {
  if (e instanceof Error && e.message === "Received a duplicate file chunk") {
    // duplicated frame: abort transfer; dedupe-and-continue is unsafe because chunk accounting breaks
  }
  throw e;
}

Prevention

When it happens

Trigger: Sender retries a failed socket.send and the original frame also arrives; multiple data sockets assigned overlapping chunk indices (stride scheduling bug); relay duplicates a frame; sender re-sends a range after a reconnect while the receiver kept partial state.

Common situations: Flaky connection where sender-side retry logic duplicates frames; reconnect/resume logic that restarts a file from offset 0 while received positions persist; more data sockets on sender than recipient (port list mismatch) shifting chunk-to-socket assignment; proxies that duplicate WebSocket frames.

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/d052e9918d1ad7fe. Report an issue: GitHub.