affaan-m/ECC · error · anyhow::Error
Completed sessions cannot be resumed: {}
Error message
Completed sessions cannot be resumed: {} What it means
The resume_session_with_program function guards against resuming a session whose state is Completed. A completed session has finished its lifecycle and cannot be resumed — its worktree may have been merged, its process has exited, and its state is final. The check fires before any state mutation or process spawning.
Source
Thrown at ecc2/src/session/manager.rs:1516
.ok_or_else(|| anyhow::anyhow!("Session not found: {session_id}"))?;
ToolLogger::new(db).query(&session.id, page, page_size)
}
pub async fn resume_session(db: &StateStore, cfg: &Config, id: &str) -> Result<String> {
resume_session_with_program(db, cfg, id, None).await
}
async fn resume_session_with_program(
db: &StateStore,
_cfg: &Config,
id: &str,
runner_executable_override: Option<&Path>,
) -> Result<String> {
let session = resolve_session(db, id)?;
if session.state == SessionState::Completed {
anyhow::bail!("Completed sessions cannot be resumed: {}", session.id);
}
if session.state == SessionState::Running {
anyhow::bail!("Session is already running: {}", session.id);
}
db.update_state_and_pid(&session.id, &SessionState::Pending, None)?;
if let Some(worktree) = session.worktree.as_ref() {
if let Err(error) = worktree::sync_shared_dependency_dirs(worktree) {
tracing::warn!(
"Shared dependency cache sync warning for resumed session {}: {error}",
session.id
);
}
}
let runner_executable = match runner_executable_override {
Some(program) => program.to_path_buf(),
None => std::env::current_exe().context("Failed to resolve ECC executable path")?,View on GitHub (pinned to 01e15490f0)
Solutions
- Create a new session instead of resuming a completed one
- Check session.state == SessionState::Completed before calling resume and show a user-facing message
- If you need to re-run the same task, clone the session configuration into a new session
- Track terminal state in the caller so resume is only offered for non-terminal sessions
Example fix
// before
resume_session(db, cfg, &id).await?;
// after
let session = resolve_session(db, &id)?;
if session.state == SessionState::Completed {
return Err(anyhow!("Session {} is completed; create a new session to re-run", id));
}
resume_session(db, cfg, &id).await?; Defensive patterns
Strategy: type-guard
Validate before calling
let session = resolve_session(db, id)?;
if session.state == SessionState::Completed {
return Err(anyhow!("Session {} is already completed. Create a new session to re-run.", id));
} Type guard
fn is_resumable(session: &Session) -> bool {
!matches!(session.state, SessionState::Completed | SessionState::Running)
} Prevention
- Disable resume buttons in UIs for sessions in terminal states
- Store terminal-session IDs in a separate list so they are not offered for resume
- Create a new session with the same task instead of trying to resume a completed one
When it happens
Trigger: Calling resume_session(db, cfg, id) or resume_session_with_program(...) for a session whose state is SessionState::Completed.
Common situations: Trying to resume a session that finished normally. Replaying a session ID from logs after it already completed. UI 'resume' button that does not check terminal state first.
Related errors
- Session is already running: {}
- Cannot merge active session {} while it is {}
- Cannot rebase active session {} while it is {}
- Cannot delete active session {} while it is {}
- Work item ${target.id} is already done; cannot claim.
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/ca8fcb1e9bc518d8.
Report an issue: GitHub.