# How Croc Supports Reconnection and Resuming Interrupted Transfers

> Learn how Croc ensures reliable file transfers by automatically resuming interrupted transfers through reconnection, exponential backoff, and chunk-level resumption.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: internals
- Published: 2026-07-26

---

**Croc automatically detects network disconnections, implements exponential backoff with a 10-attempt limit, negotiates resume protocol versions with peers, and transfers only missing chunks to seamlessly resume interrupted file transfers.**

Croc is an open-source command-line file transfer tool designed to survive flaky networks where traditional tools would fail completely. When TCP connections drop mid-transfer, croc does not terminate the process; instead, it enters a sophisticated reconnection routine that negotiates fresh relay rooms and resumes exactly where the transfer left off. This article examines the specific mechanisms in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go), and supporting modules that make interruption-tolerant transfers possible.

## Detecting Transfer Interruptions

### Identifying Disconnects with transferDisconnectError

When a TCP link drops, croc wraps the underlying error in a custom `transferDisconnectError` type defined in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) lines 302-306. The helper function `isTransferDisconnectError` (lines 93-96) recognizes this wrapper and distinguishes between fatal errors (like corrupted files) and recoverable network drops (like WiFi hiccups or mobile handoffs). Upon detection, croc triggers the reconnection routine instead of exiting.

## Reconnection Strategy and Backoff Mechanisms

### Limiting Retry Attempts

The reconnection logic respects a hard ceiling defined by `maxReconnectAttempts` in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) lines 55-56, which defaults to **10 attempts**. This prevents infinite retry loops against permanently offline peers while accommodating temporary network fluctuations.

### Exponential Backoff Timing

Between attempts, croc implements `reconnectBackoff` (lines 79-90) to calculate delays using exponential backoff capping at 5 seconds. This reduces relay server load and allows transient network issues to resolve naturally.

### Generating Fresh Relay Rooms

To resume a transfer, croc must establish a new communication channel independent of the broken connection. The `generateReconnectRoom` function (lines 71-77) creates a cryptographically random room name for the resumed session, ensuring the client and sender can reconnect through the relay without interfering with other active transfers or the stale session.

## Negotiating Resume Protocol Versions

Before exchanging file data, croc ensures both peers speak the same resume protocol. The client maintains a `reconnectVersion` (lines 52-54 in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go)) exchanged during the handshake. If the peer reports a higher version (`peerReconnectVersion`), the client immediately adopts it, guaranteeing backward and forward compatibility during the resume process.

## Resuming Interrupted Transfers with Chunk Ranges

### Requesting Missing Chunks via RemoteFileRequest

Once the reconnection handshake completes, the receiver transmits a `RemoteFileRequest` (lines 104-110) containing the specific byte ranges or chunks still needed to complete the file. The sender responds by transmitting only those missing pieces rather than restarting the entire transfer from byte zero.

### Handling Large Resume Payloads

For transfers involving multi-gigabyte files, the list of missing chunks can become substantial. To prevent timeouts during this control phase, [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go) line 30 raises the `messageBodyReadTimeout` to **10 minutes**, ensuring that extensive chunk lists can traverse slow relays without dropping the connection.

### Completing the Transfer

The sender finalizes the resume by executing `finishSender` (lines 51-69 in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go)), writing only the requested missing chunks to the wire while the receiver writes them to the appropriate offsets in the target file. The underlying TCP wrapper in [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go) and connection logic in [`src/tcp/tcp.go`](https://github.com/schollz/croc/blob/main/src/tcp/tcp.go) handle the actual byte streaming during this phase.

## CLI Options for Automatic Resume

### Using the Overwrite Flag

According to [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go) line 125, users can invoke the `--overwrite` flag to automatically attempt resuming interrupted transfers without interactive prompting. Without this flag, croc asks for user confirmation unless `--no-prompt` is also set.

**Resume a transfer automatically with default behavior:**

```bash
croc send --code abcdef large-file.zip        # Start transfer

# ... network drops ...

croc receive --code abcdef                     # Re-run the same command

# croc detects the previous session, creates a new relay room,

# asks for missing chunks, and continues.

```

**Force resume without prompting:**

```bash
croc receive --code abcdef --overwrite         # Skip the "overwrite?" prompt

```

**Programmatic handling of disconnections:**

```go
if err != nil {
    if croc.IsTransferDisconnectError(err) {
        // Reconnection logic is embedded in croc.Client.Start()
        // Simply allow Start() to continue or call it again.
    }
}

```

## Summary

- **Error Detection:** Croc wraps TCP errors in `transferDisconnectError` ([`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) lines 302-306) to identify recoverable network drops.
- **Retry Limits:** The client attempts reconnection up to 10 times with exponential backoff (max 5 seconds) via `maxReconnectAttempts` and `reconnectBackoff`.
- **Fresh Channels:** `generateReconnectRoom` creates new random room names to avoid session conflicts.
- **Version Negotiation:** `reconnectVersion` ensures both peers agree on the resume protocol before exchanging data.
- **Partial Transfer:** `RemoteFileRequest` requests only missing chunks, while `messageBodyReadTimeout` (10 minutes in [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go) line 30) accommodates large chunk lists.
- **CLI Control:** The `--overwrite` flag in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go) line 125 enables automatic resume without user intervention.

## Frequently Asked Questions

### How many times will croc attempt to reconnect before giving up?

Croc defaults to **10 reconnection attempts** as defined by `maxReconnectAttempts` in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) lines 55-56. After exhausting these attempts, the transfer terminates and returns an error.

### Does croc restart the entire file when resuming a transfer?

No. Croc uses `RemoteFileRequest` (lines 104-110) to communicate exactly which chunks are missing. The sender then transmits only those pieces via `finishSender` (lines 51-69), appending them to the partially received file without restarting from byte zero.

### What happens if the sender and receiver have different versions of croc?

The resume protocol includes version negotiation through `reconnectVersion` and `peerReconnectVersion` (lines 52-54). Both sides automatically adopt the higher version number, ensuring backward compatibility and preventing protocol mismatches during reconnection.

### How long will croc wait for a large list of missing chunks to transfer?

Croc sets `messageBodyReadTimeout` to **10 minutes** in [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go) line 30 specifically for resume control messages. This extended timeout accommodates huge file manifests that might otherwise timeout on slow relays, while normal data chunks use shorter deadlines.