affaan-m/ECC · error

Session has no attached worktree

Error message

Session {} has no attached worktree

What it means

Thrown when performing a worktree merge/cleanup for a session whose optional worktree field is None. The operation requires an attached git worktree, so the code converts the missing value into 'Session {id} has no attached worktree' rather than proceeding with a default.

Solutions

  1. Check session.worktree before invoking the merge; skip sessions without one.
  2. Only run the merge for sessions created with worktree support (enable auto_create_worktrees or recreate the session with a worktree).
  3. If the worktree was already merged and cleaned up, treat this outcome as a no-op, not an error.
  4. Inspect the session record (e.g. session show) to confirm worktree state first.

Example fix

// before
merge_worktree(db, &session_id, true)?; // session has no worktree
// after
let session = db.get_session(&session_id)?.ok_or_else(|| anyhow::anyhow!("no such session"))?;
if session.worktree.is_some() {
    merge_worktree(db, &session_id, true)?;
} else {
    eprintln!("session {session_id} has no worktree; nothing to merge");
}
Defensive patterns

Strategy: type-guard

Validate before calling

let has_worktree = db.get_session(&session_id)?
    .and_then(|s| s.worktree)
    .is_some();

Type guard

fn has_worktree(s: &Session) -> bool { s.worktree.is_some() }
// if !has_worktree(&session) { skip merge }

Try / catch

match merge_worktree(db, id, cleanup) {
    Err(e) if e.to_string().contains("has no attached worktree") => {
        eprintln!("nothing to merge for {id}");
        Ok(())
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling the merge/worktree-cleanup flow for a session created without worktrees (auto_create_worktrees disabled) or one whose worktree was already merged/removed.

Common situations: Running the merge command twice (second time the worktree was cleared), sessions started with --no-worktree, or config where auto_create_worktrees=false.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/c39d7a95d4f6ee22. Report an issue: GitHub.

Appendix: source

Thrown at ecc2/src/session/manager.rs:1793

    cleanup_worktree: bool,
) -> Result<WorktreeMergeOutcome> {
    let session = resolve_session(db, id)?;

    if matches!(
        session.state,
        SessionState::Pending | SessionState::Running | SessionState::Idle | SessionState::Stale
    ) {
        anyhow::bail!(
            "Cannot merge active session {} while it is {}",
            session.id,
            session.state
        );
    }

    let worktree = session
        .worktree
        .clone()
        .ok_or_else(|| anyhow::anyhow!("Session {} has no attached worktree", session.id))?;
    let outcome = crate::worktree::merge_into_base(&worktree)?;

    if cleanup_worktree {
        crate::worktree::remove(&worktree)?;
        db.clear_worktree(&session.id)?;
    }

    Ok(WorktreeMergeOutcome {
        session_id: session.id,
        branch: outcome.branch,
        base_branch: outcome.base_branch,
        already_up_to_date: outcome.already_up_to_date,
        cleaned_worktree: cleanup_worktree,
    })
}

pub async fn rebase_session_worktree(db: &StateStore, id: &str) -> Result<WorktreeRebaseOutcome> {
    let session = resolve_session(db, id)?;

View on GitHub (pinned to 8321021c54)