Failure Modes

Things will go wrong. This page lists the failure modes that Dropbear is designed to handle, what they look like from the outside, and what you do about them.

Network Blip

What happens: the run aborts with a stage-specific exit code (10 transient, 11 integrity, 12 list).

On disk: nothing destructive. The state DB still reflects the pre-sync world, the bucket has whatever was uploaded so far (orphan blobs — harmless; future GC will reclaim).

What you do: rerun dropbear sync. The pipeline is idempotent — blobs that already exist in the bucket are skipped, the manifest is rebuilt from scratch, the head is republished. There is no "partial sync to clean up."

Device Unplugged

What happens: dropbear sync fails identity validation and exits with code 3 (offline).

On disk: nothing.

In the bucket: nothing. Crucially, no tombstones are emitted for the files Dropbear can't currently see. A USB drive being unplugged is not a delete.

What you do: plug the drive in. Rerun.

Auth Revoked

What happens: exit code 9 (unauthorized) at whichever pipeline stage first hits the bucket.

On disk: nothing.

What you do: rotate / refresh credentials in your DROPBEAR_S3_* environment, rerun.

Hash Mismatch

What happens: during the download phase, Dropbear fetches another device's head, then fetches the manifest it points to, and verifies that the manifest's bytes hash to manifest_sha256 from the head. If they don't match, the run aborts with exit code 11.

Why it matters: either the bucket has been tampered with, or you've hit a bug. Either way, Dropbear refuses to proceed because a forged manifest could direct your device to download an attacker-chosen blob under an existing path.

What you do: investigate. The bucket should not produce mismatched objects under normal operation. If you have a bug report, this is one.

Simultaneous Edits

What happens: the device that pulls second sees that its local file diverges from the manifest entry it pulled. Instead of overwriting, it writes a conflict copy: <stem>.conflict-<other-device-id>-<UTC-timestamp>.<extension>. The local row flips to StatusConflict, which excludes it from this device's manifest until you resolve.

On disk: both versions present. Original at the original path; the other device's version in the conflict-suffixed file.

What you do: look at both, pick a winner, delete the conflict file, edit the local file if needed. The next sync republishes the resolved state. (A future dropbear resolve command will make this less of an implicit dance.)

Multi-Device Disagreement

What happens: three or more devices have diverged on the same path and Dropbear can't decide which device's content to materialize as the conflict file. The run skips that path with a warning and leaves local untouched. The path stays in conflict-skip status until enough devices re-converge that the divergence has a clear winner, or the user manually resolves.

What you do: consolidate edits on one device, or use download-only / upload-only modes to break the symmetry.

Remote Head Fetch Fails

What happens: transient errors or auth blips on a specific device's head are reported as a skip counter (warning to stderr; the rest of the run continues). That device's content does not influence this run, but the next run will retry.

What you do: nothing immediate. If a specific device is consistently skipped, that's worth investigating.

Disk Full

What happens: the download writes to a temp dir under the root and atomically renames into place on success. A disk-full failure leaves the temp dir, aborts the run with a stage error.

On disk: orphan temp directories under .dropbear/restore-tmp/. Cleaned up automatically on the next run.

What you do: free space, rerun.

State DB Corrupted

What happens: the SQLite file under .dropbear/state.sqlite is unreadable.

What you do: you can rebuild local state from the bucket using dropbear restore --from <your-device-id> — it repopulates the state DB from the manifest you last published. You lose any unpublished work since that manifest. If you have unpublished changes, copy them aside first.

Escape Hatch

If you've lost confidence in a root's local state — botched edit, weird metadata, suspected bug — you can always:

  1. Copy your live working files aside.
  2. Delete .dropbear/state.sqlite.
  3. Run dropbear restore --from <your-device-id> to repopulate from the bucket.
  4. Compare your set-aside copy with the restored state and merge by hand.

This isn't pretty, but it's always available as an escape hatch because the bucket is the source of truth.