schollz/croc · error · Error

Received more data than the advertised file size

Error message

Received more data than the advertised file size

What it means

Thrown inside DataReceiver.accept when the accumulated byte count for the active file exceeds the advertised size. The aligned-position check should prevent overshoot, so reaching this branch means total received bytes (counting every accepted chunk) went past file.size — e.g. overlapping-but-not-duplicate offsets after rounding, or a size advertisement smaller than the true file. It is a final consistency backstop that fails the transfer before finalize/verify.

Source

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

      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");
      }
    });
    active.queue.catch((error) => {
      if (this.active === active) this.active = undefined;
      active.reject(error instanceof Error ? error : new Error(String(error)));
    });
    return active.queue;
  }
}

export async function receiveFiles(options: {
  secret: string;
  settings: TransferSettings;
  callbacks: ReceiveCallbacks;
  signal?: AbortSignal;
}) {
  const { secret, settings, callbacks, signal } = options;
  validateSecret(secret);

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Guarantee the file is immutable from hashing through streaming; snapshot large/active files before prepareFiles
  2. Cross-check prepared.size against the actual bytes sliced in sendFileData in tests
  3. Treat this error as evidence of sender-side state drift — re-prepare files and restart the transfer
  4. If it reproduces deterministically at file end, log chunkCount, final position, and advertised size to find the off-by-one
Defensive patterns

Strategy: validation

Validate before calling

// Sender-side: snapshot mutable files before hashing so size cannot drift
const snapshot = await file.slice(0, file.size).arrayBuffer(); // then hash/stream from the snapshot

Try / catch

catch (e) {
  if (e instanceof Error && e.message === "Received more data than the advertised file size") {
    // sender streamed past its own advertisement: re-prepare files and restart
  }
  throw e;
}

Prevention

When it happens

Trigger: Sender advertises size N in fileinfo but streams more than N bytes (file grew after hashing); rounding in chunkCount math (Math.ceil(size/CHUNK_SIZE)) sending a full final chunk where a partial one was expected and position checks passed; a peer sending an extra chunk past the final aligned offset with distinct positions.

Common situations: The sender's file is appended to (log file, download in progress) between prepareFiles and the transfer loop; inconsistent size fields between senderInfo and sendFileData; adversarial sender probing the receiver's bounds checks.

Related errors


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