Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Recovery and Resume

Rivet stores export progress in a SQLite state file (.rivet_state.db) located next to the config file. This guide covers how to inspect, resume, and reset export state correctly.


State file location

The state file is always created next to the config file:

./rivet.yaml          ← config
./.rivet_state.db     ← state (created automatically on first run)

To use a different location, point --config at the desired directory.


Export modes and state

ModeWhat is storedResume behaviour
fullCompleted file list (manifest)No resume needed — re-run starts a fresh export
incrementalLast cursor valueRe-run starts from where it left off
chunkedPer-chunk completion status--resume continues from the last completed chunk
time_windowNothing — no cursor is storedEach re-run re-evaluates the rolling window from NOW(); windows overlap by design
cdcLog position (PostgreSQL slot / MySQL binlog checkpoint / SQL Server LSN / MongoDB resume token)Resumes streaming from the last committed change position

--resume for chunked exports

--resume is only meaningful for chunked mode with chunk_checkpoint: true (not the default — set it so progress is recorded per chunk). It requires an in-progress (not yet completed) checkpoint run in the state file. On a full/incremental export --resume has no effect and warns.

Resume an interrupted export

# Start the export
rivet run --config rivet.yaml --export big_table

# If it was interrupted, resume it
rivet run --config rivet.yaml --export big_table --resume

What happens if no checkpoint exists

If --resume is called without a prior in-progress run, Rivet exits non-zero with a clear message:

error: --resume requires an in-progress chunked export in state;
       run without --resume to start a fresh export.

Do not use --resume to start a fresh export. It is only for continuing interrupted runs.

What happens after a completed export

After a chunked export completes normally, --resume also exits non-zero:

error: --resume found a completed export (not in-progress);
       use `rivet run` (without --resume) to start a new run.

This prevents accidentally treating a completed export as resumable.

--resume on full or incremental mode

--resume is silently validated for full/incremental exports — a plan validation warning is emitted:

[resume-no-checkpoint] export 'X': --resume has no effect on full/incremental
exports. Remove --resume to suppress this warning.

The export proceeds normally. The flag is ignored.


Inspecting state

rivet state show --config rivet.yaml

This shows the current cursor value for each incremental export. For chunk completion status use rivet state chunks --config rivet.yaml --export big_table, and for per-run history (rows, bytes, duration, peak RSS) use rivet metrics --config rivet.yaml.


Resetting state

Reset cursor for incremental exports

rivet state reset --config rivet.yaml --export incremental_export

The next run will re-export all rows from the beginning.

Reset chunk state for chunked exports

rivet state reset-chunks --config rivet.yaml --export big_table

After reset, the next rivet run (without --resume) starts fresh from chunk 0.

Important: After reset-chunks, do not use --resume — there is no checkpoint to resume from.


Common operator mistakes

Mistake 1: Using --resume after reset

rivet state reset-chunks --config rivet.yaml --export big_table
rivet run --config rivet.yaml --export big_table --resume  # WRONG

Fix: omit --resume after a reset.

rivet run --config rivet.yaml --export big_table  # correct

Mistake 2: Using --resume to start a fresh chunked export

# First run ever — no state exists
rivet run --config rivet.yaml --export big_table --resume  # WRONG

Fix: do not use --resume on the first run.

Mistake 3: Pointing to a different config file for resume

The state file is tied to its config directory. If you copy the config to a new location, the state file is not copied with it — the resumed export starts fresh.


Crash recovery

If the process is killed mid-export:

  • Incremental — the cursor is committed once per run, after the run’s manifest is durable. A crash mid-export leaves the cursor at the previous run’s value, so re-running re-exports the whole window — into new, uniquely-timestamped part files (names embed a per-run millisecond stamp). Files the crashed run already committed are complete, never partial, and are not overwritten — they remain in the prefix as at-least-once duplicates, which downstream consumers must tolerate (load from the manifest, see semantics.md).

  • Chunked — each chunk is committed to state only after it writes successfully. A crash mid-chunk means that chunk is retried on --resume. Completed chunks are not re-exported. This holds for both the sequential checkpoint loop (parallel: 1) and the parallel worker pool (parallel: N with chunk_checkpoint: true); when one parallel worker panics, reset_stale_running_chunk_tasks resets every running task back to pending on resume so no work is lost. Coverage: live_chunked_recovery C1–C4 (see reliability-matrix.md § Failure-mode coverage).

  • Full — full exports have no cursor. Re-running after a crash starts from the beginning and writes new, uniquely-timestamped part files; anything the crashed run left behind stays in the prefix as an orphan (no manifest names it) — load from the manifest, or clean orphans with gc_orphans.


See also