Fix "corrupt session log: seq gap" in DeepSeek Harness
A DeepSeek Harness session that fails with Error: corrupt session log: seq gap in committed region is almost always caused by two processes writing the same DSH_HOME concurrently — the most common shape is the desktop app and the web UI open at the same time. An interrupted tool call magnifies the collision. Back up your data, keep a single instance, and export the broken session for the record.
What the DeepSeek Harness session log seq gap error looks like
The error has a fixed shape: corrupt session log: seq gap in committed region at line N (expected X, got Y), after which that session will not open. A user hit this in the wild (see the discussion):
- Open an old session — it immediately fails with
seq gap in committed region at line 1649 (expected 5259, got 5255); - The session is unopenable in the list while every other session works;
- Inspecting the log shows the same seq range written twice: first the crash-recovery placeholder events (
tool/result isError=true→step/end→turn/end→session/end-seed), then the same tool call's real result rewritten from the same seq again.
The user first read this as "the retry reused old seqs", but the accepted answer revealed the real story: from a single log it looks like a retry, but two processes are involved. One process recovered the session and committed the synthetic closing events; the other, still live, committed the same tool call's real result starting from its own cursor. The JSONL backend coordinates nothing across processes, so both batches "pass" their own validation and overlapping seqs hit the disk.
DSH session seq gap root cause: desktop and web UI writing concurrently
Two conditions stack to make this nearly certain: the same DSH_HOME open in two live instances, plus an interrupted tool call somewhere in between. Broken down:
- Two instances is the necessary condition: starting a
dsh webdesktop wrapper inside a GUI session gives two processes pointing at the sameDSH_HOME; - Interruption amplifies it: cancelling a long-running tool call (e.g.
bashrunningsleep 30) triggers a crash-recovery path that synthesizes and persists a batch of closing events; - No cross-process coordination: each process validates its batch against its own in-memory cursor (
appendCorechecksevent.seq === state.cursor + i), so both write and both "pass"; - The session subsystem docs already name this gap: tolerating concurrent writers needs a signal beyond the log.
That also explains why this is hard to trigger deliberately and suddenly reproducible — it needs two live instances on one DSH_HOME.
How to recover a DSH session that won't open: back up, single instance, new session
Recovery in three moves: back up first, then keep one instance, then continue in a new session. Hand-editing the log file is not recommended.
- Stop every DeepSeek Harness instance immediately: close the desktop app and
Ctrl+Cthedsh webin the browser to stop further concurrent writes; - Check the version and running processes to confirm the double-writer is the source: run
dsh --version, then list processes to see how many instances share the sameDSH_HOME(macOS/Linux):
dsh --version
ps aux | grep -E 'dsh|deepseek' | grep -v grep
On Windows, use tasklist | findstr /i dsh instead. More than one live instance means concurrent writes are happening;
- Back up the broken session: locate the session file (
session.jsonl.zstdunder~/.dsh/profiles/<name>/sessions/) and copy it somewhere safe:
ls -lh ~/.dsh/profiles/<name>/sessions/
cp ~/.dsh/profiles/<name>/sessions/<session-file>.jsonl.zstd /tmp/dsh-session-backup/
- Restart a single instance (desktop app or
dsh web, pick one) — the old session staying unopenable is expected; it has been flagged as corrupt; - Start a new session to keep working, and manually carry over anything important from the broken one;
- Going forward, stick to one instance: do not keep the desktop app and the web UI on the same
DSH_HOMEat the same time, especially if you interrupt tool calls.
seq gap fix status: DeepSeek Harness cross-process lock patch awaiting merge
Discussion #4662 provides a fuller reconstruction and a published fix branch: a cross-process writer lock serializes appends, and a process with a stale cursor is rejected instead of writing overlapping seqs. The highlights:
- Appends take a cross-process writer lock and, while holding it, must continue the durable tail;
- A process whose cursor lags the durable tail gets a diagnostic and is rejected (reject-never-repair: a stale cursor should resume the session, not patch the file);
- The commenter is running the branch in production and added a performance review for the tail read (see that thread);
- Until it lands upstream, "single instance + backups" as described above is the reliable workaround.
Notes
- The line number and seq values change every time — this is the artifact of concurrent writes, not data loss. The conversation content is most likely still there; only the log cannot replay.
- Do not hand-edit seq values in
session.jsonl.zstd: you would also have to fix surface references and token projections, and one wrong step cascades into more corruption. - Related session problems are collected in the DeepSeek Harness plugin error collection: Web UI issues and session cache fixes tutorial — check it alongside this one.
Sources: Discussion #4598, Discussion #4662
FAQ
Two processes are writing the same DSH_HOME concurrently — typically the desktop app and dsh web running at the same time. Each validates against its own in-memory cursor while the JSONL backend coordinates nothing across processes, so overlapping seqs are written and the load fails with seq gap in committed region (source: Discussion #4598).
On interrupt, one process synthesizes and commits a batch of closing events (tool/result isError=true → step/end → turn/end → session/end-seed); the other, still-live process then continues the same tool call from its own old cursor. The two batches overlap on the same seq range, so log corruption is almost certain.
Back up the session file first (session.jsonl.zstd under ~/.dsh/profiles/<name>/sessions/), confirm with ps aux (tasklist on Windows) that no second instance is running, keep only the desktop app or dsh web, then continue in a new session. Hand-editing seq values also requires fixing surface references and token projections, so it is not recommended for regular users.
Discussion #4662 ships a cross-process writer lock: appends are serialized and must continue the durable tail, and a process with a stale cursor is rejected with a diagnostic instead of writing overlapping seqs (source: Discussion #4662). It is waiting to be merged upstream; once released, update to a build whose dsh --version includes the patch.
Sources
- deepseek-harness Discussion #4598: interrupted tool call retry reuses old seq, corrupting the session log· deepseek-ai (GitHub Discussions)
- deepseek-harness Discussion #4662 (fuller reconstruction and a fix branch for the same bug)· deepseek-ai (GitHub Discussions)