# Atlas SessionBusyError: session is busy

> Wait for the current generation to finish, or cancel it with the TUI interrupt binding, then retry: SessionRunState.assertNotBusy rejects mutating operations on a running session.

Atlas throws SessionBusyError, carrying the sessionID, because SessionRunState.assertNotBusy guards mutating operations: revert, unrevert, and startShell all assert the session is idle first, so concurrent writes to the same session are rejected rather than interleaved. The fix is to wait for the current generation to finish, or cancel it with the TUI interrupt binding, then retry. Do not work around it by opening a second session against the same worktree.

## Symptom

An operation fails with SessionBusyError carrying the sessionID. Reverting, unreverting, or starting a shell in a session that is already generating all hit this error.

## Cause

SessionRunState.assertNotBusy guards mutating operations. Revert, unrevert, and startShell all assert the session is idle first, so concurrent writes to the same session are rejected rather than interleaved.

## Fix

1. Wait for the current generation to finish, or cancel it, then retry the operation.
2. Cancel with the TUI interrupt binding; SessionRunState.cancel exists precisely for this.
3. If you are driving Atlas from the server API, poll for the session to leave the running state before issuing the write.
4. Do not work around it by opening a second session against the same worktree.

## Why does Atlas throw SessionBusyError

Atlas throws SessionBusyError because SessionRunState.assertNotBusy guards mutating operations on a session that is already generating. The error carries the sessionID, and in the 2026 source revert, unrevert, and startShell all assert the session is idle before they will touch it.

SessionBusyError is a concurrency guard, not a crash. A generating session is actively producing messages and may be writing files, so allowing a revert to run underneath it would interleave two writers against the same state. SessionRunState.assertNotBusy refuses that instead. The sessionID on the error tells you exactly which session is occupied, which matters when you are running several sessions at once and only one of them is mid-generation. The three operations that trip it are the mutating ones: reverting, unreverting, and starting a shell in a session that is already generating.

## How to fix SessionBusyError in Atlas

Fix SessionBusyError in Atlas by waiting for the current generation to finish, or by cancelling it, then retrying. There are only 2 ways out, wait or cancel. SessionRunState.assertNotBusy rejects the call while the session is busy, so the same revert or unrevert succeeds once the session returns to idle.

Waiting is often the whole fix, especially for a generation that is close to done. When you do not want to wait, cancel with the TUI interrupt binding: SessionRunState.cancel exists precisely for this, and it returns the session to a state where mutating operations are allowed again. After the cancel lands, re-issue the revert, unrevert, or startShell call that failed. There is no flag to force the write through while the session is busy, and that is intentional, because concurrent writes to the same session are rejected rather than interleaved.

## How to cancel a generating Atlas session

Cancel a generating Atlas session with the TUI interrupt binding. SessionRunState.cancel exists precisely for this case, and cancelling is the faster of the 2 exits from SessionBusyError when you do not want to wait for the current generation to finish on its own.

Cancellation stops the in-flight generation and releases the guard that SessionRunState.assertNotBusy enforces. Atlas is a terminal-native TUI rendered with SolidJS through the OpenTUI renderer, so the interrupt is a keybinding in the interface rather than a signal you send to the process from outside. Cancel, confirm the session has settled, then retry the operation. Be honest about what cancelling costs: the model turn in progress ends where it ends, so any partial reasoning in that turn is discarded, and you may need to re-ask the question afterward.

## How to handle a busy Atlas session from the server API

If you are driving Atlas from the server API, poll for the session to leave the running state before issuing the write. SessionRunState.assertNotBusy guards 3 operations, revert, unrevert, and startShell, and rejects each of them against a generating session with SessionBusyError carrying the sessionID.

API callers hit this more often than TUI users, because a script has no visual cue that a generation is in flight and will happily fire a write the instant the previous request returns. Build the wait into the client: check the session state, back off, and only then send the mutating call. Treat SessionBusyError as a retryable signal rather than a fatal one, since the same request succeeds once the session is idle. The sessionID on the error is what you key your retry against when your client is managing several sessions concurrently.

## Should I open a second Atlas session on the same worktree

Do not work around SessionBusyError by opening a 2nd Atlas session against the same worktree. SessionRunState.assertNotBusy rejects concurrent writes to 1 session deliberately, and a second session on the same files reintroduces exactly the interleaving that the guard exists to prevent.

Two sessions editing one worktree will fight over the same files, and neither one has a view of what the other is doing. Atlas snapshots file changes as git patches so edits can be diffed and rolled back, and Atlas computes a unified diff for every file edit and surfaces it for approval before writing, but neither of those protections is designed to arbitrate between two independent sessions writing the same paths at once. If you need parallel work, give each session its own worktree, or fan the work out to subagents from a single session instead.

## FAQ

### how to fix SessionBusyError in Atlas

Wait for the current generation to finish, or cancel it with the TUI interrupt binding, then retry. SessionRunState.assertNotBusy rejects revert, unrevert, and startShell while the session is generating.

### why can I not revert while an Atlas session is generating

SessionRunState.assertNotBusy guards mutating operations. Revert, unrevert, and startShell all assert the session is idle first, so concurrent writes to the same session are rejected rather than interleaved.

### how do I cancel a running Atlas generation

Use the TUI interrupt binding. SessionRunState.cancel exists precisely for this, and cancelling returns the session to idle so mutating operations are allowed again.

### what does the sessionID on SessionBusyError tell me

SessionBusyError carries the sessionID of the session that is busy, which identifies exactly which session is mid-generation when you are running several at once.

### how should the Atlas server API handle a busy session

Poll for the session to leave the running state before issuing the write. Treat SessionBusyError as retryable, since the same revert or unrevert succeeds once the session is idle.

### can I run two Atlas sessions on the same worktree

Do not do it as a workaround for SessionBusyError. Two sessions writing the same files reintroduce the interleaving the busy guard prevents. Use a separate worktree per session instead.

---

Canonical HTML: https://runatlas.sh/resources/troubleshooting/session-is-busy
Source of truth: aeo_pages row `/resources/troubleshooting/session-is-busy` (segment: Troubleshooting) (this file is generated from it, never hand-edited).
Licence: Atlas is proprietary with a free core. It is not open source and there is no public source repository.
