# How Croc Handles Transfer Interruptions and Reconnections

> Learn how croc automatically handles transfer interruptions and reconnections. It retries failed transfers with exponential backoff and resumes only missing file chunks.

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

---

**Croc detects broken TCP connections using `transferDisconnectError`, then automatically retries up to 10 times with exponential backoff while negotiating a new relay room and requesting only missing file chunks to resume interrupted transfers.**

Croc is engineered to survive flaky networks and sudden drops. When a connection fails during a file transfer, the `schollz/croc` repository does not simply terminate; instead, it executes a sophisticated reconnection protocol that preserves progress and minimizes retransmission. This resilience is implemented through error wrapping, backoff strategies, and delta synchronization directly in the Go source code.

## Detecting Disconnections with `transferDisconnectError`

When the underlying TCP link drops, croc immediately wraps the error in a `transferDisconnectError` structure. In [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) at lines 302‑306, the library defines this wrapper to distinguish between fatal errors and transient network failures. The function `isTransferDisconnectError` at lines 93‑96 then inspects the error chain to determine if a retry is appropriate, triggering the reconnection routine only when the disconnect is identified as recoverable.

## Reconnection Strategy: Backoff and Room Generation

Once a disconnect is detected, croc enters a controlled retry loop governed by three key mechanisms defined in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go):

- **`maxReconnectAttempts`** (lines 55‑56): Caps retries at **10 attempts** by default to prevent infinite loops.
- **`reconnectBackoff`** (lines 79‑90): Implements **exponential backoff** with a maximum delay of **5 seconds** between attempts.
- **`generateReconnectRoom`** (lines 71‑77): Creates a **fresh random room name** for the resumed session, ensuring the new connection bypasses any stale relay state.

This combination prevents thundering herds while giving the network time to recover.

## Version Negotiation Protocol

To ensure both endpoints speak the same resume language, croc exchanges versioning tokens during reconnection. The client maintains a `reconnectVersion` constant (lines 52‑54) and compares it against the `peerReconnectVersion` reported by the remote side. If the peer reports a higher version, the adopting client upgrades its protocol accordingly, guaranteeing backward compatibility during intermittent reconnections.

## Resuming Transfers with `RemoteFileRequest`

After establishing a new relay room and agreeing on protocol versions, the receiver sends a `RemoteFileRequest` (lines 104‑110) that lists specific chunk ranges still needed to complete the file. The sender then invokes `finishSenderData` (lines 51‑69) to transmit only those missing pieces rather than restarting from byte zero. This delta synchronization dramatically reduces bandwidth usage on large files.

## TCP Timeout Adjustments for Resume Payloads

Standard TCP timeouts are too aggressive for resume operations that must transmit large control messages. In [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go) at line 30, croc raises the read deadline to **10 minutes** via `messageBodyReadTimeout` specifically for resume-control messages. This ensures that even massive "missing-chunk" lists can traverse slow or high-latency relays without triggering premature timeouts.

## CLI Flags for Automatic Resume Behavior

User interaction during resume is controlled through flags defined in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go). At line 125, the **`--overwrite`** flag automatically attempts to resume an interrupted transfer without prompting. When combined with **`--no-prompt`**, croc becomes fully autonomous, silently recovering from network interruptions using the stored session state.

## Practical Usage Examples

Resume a transfer automatically using the default behavior:

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

# … network drops …

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

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

# asks the sender for missing chunks and continues.

```

Force resume without user interaction:

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

```

Programmatically check for disconnects in Go:

```go
if err != nil {
    if croc.IsTransferDisconnectError(err) {
        // retry logic is embedded in croc.Client.Start()
        // simply call Start() again or let croc handle the reconnection.
    }
}

```

## Summary

- **Error Detection**: Uses `transferDisconnectError` in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) lines 302‑306 to identify recoverable network failures.
- **Retry Limits**: Enforces a maximum of **10 reconnection attempts** with exponential backoff capped at **5 seconds**.
- **Fresh Sessions**: Generates new relay rooms via `generateReconnectRoom` to avoid stale connection state.
- **Protocol Safety**: Exchanges `reconnectVersion` tokens to ensure compatible resume semantics between peers.
- **Delta Sync**: Requests missing chunks through `RemoteFileRequest` instead of retransmitting entire files.
- **Timeout Tolerance**: Extends TCP read deadlines to **10 minutes** in [`src/comm/comm.go`](https://github.com/schollz/croc/blob/main/src/comm/comm.go) for large resume payloads.

## Frequently Asked Questions

### What happens if croc exceeds the maximum reconnection attempts?

If the network remains down after **10 attempts**, croc aborts the transfer and returns the last encountered error. The exponential backoff (max **5 seconds**) ensures the process does not hammer the relay, but once the cap is reached, the user must manually restart the transfer.

### How does croc prevent version mismatches during a resumed transfer?

The client carries a `reconnectVersion` token defined at lines 52‑54 of [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go). During reconnection, both sides exchange this value; if `peerReconnectVersion` is higher, the client adopts the peer's protocol level. This handshake guarantees that sender and receiver agree on how to interpret the `RemoteFileRequest` and chunk sequencing.

### Why does croc create a new relay room instead of reusing the old one?

The `generateReconnectRoom` function (lines 71‑77) creates a new random room name to bypass potential stale state in the relay or NAT tables. TCP connections often leave ghost sessions in intermediary proxies; a fresh room ensures both endpoints negotiate a clean slate while maintaining continuity through the versioning and chunk-tracking logic.

### Can I force croc to resume without prompting the user?

Yes. Supply the **`--overwrite`** flag (line 125 in [`src/cli/cli.go`](https://github.com/schollz/croc/blob/main/src/cli/cli.go)) when running `croc receive`. This flag tells croc to automatically attempt resuming interrupted transfers. Combine it with **`--no-prompt`** for fully automated recovery in scripts or CI/CD pipelines.