shareAI-lab/learn-claude-code · error · ValueError

Assignment cwd changed for task {task.id}

Error message

Assignment cwd changed for task {task.id}

What it means

After confirming the assignment's task is still active, the system recomputes the task's worktree cwd and compares it (resolved) against the cwd stored when the lease was created. If they differ — the worktree was recreated, renamed, or moved — the lease's recorded cwd no longer matches reality and the mismatch is surfaced as ValueError instead of executing work in the wrong directory.

Source

Thrown at s13_agent_teams/code.py:409

    with task_lock:
        assignment = teammate_assignments.get(owner)
        task = _owner_in_progress(owner)
        if task and (not assignment or assignment.get("task_id") != task.id):
            cwd, error = task_worktree_cwd(task)
            if error:
                raise ValueError(error)
            assignment = {"task_id": task.id, "cwd": cwd}
            teammate_assignments[owner] = assignment
        elif not assignment:
            return WORKDIR
        task = load_task(str(assignment["task_id"]))
        if task.status not in {"in_progress", "completed"} or task.owner != owner:
            raise ValueError(f"Assignment for {owner} is no longer active")
        cwd, error = task_worktree_cwd(task)
        if error:
            raise ValueError(error)
        if cwd.resolve() != Path(assignment["cwd"]).resolve():
            raise ValueError(f"Assignment cwd changed for task {task.id}")
        return cwd


def release_completed_assignment(owner: str) -> bool:
    """Release a completed cwd lease only at a model turn boundary."""
    with task_lock:
        assignment = teammate_assignments.get(owner)
        if not assignment:
            return False
        task = load_task(str(assignment["task_id"]))
        if task.status != "completed" or task.owner != owner:
            return False
        teammate_assignments.pop(owner, None)
        advance_assignment_version(owner)
        if owner in globals().get("plan_gates", {}):
            globals()["plan_gates"][owner] = "not_required"
        return True

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Don't delete/recreate .worktrees entries for tasks that have active assignments; release the assignment first.
  2. Catch this ValueError per-owner, drop the stale lease (teammate_assignments.pop(owner)) so the next call re-derives the cwd, and retry once.
  3. Keep the workspace path stable (fully resolved) for the process lifetime.

Example fix

# before
def owner_cwd(owner):
    return cwd_for(owner)  # propagates ValueError

# after
def owner_cwd(owner):
    try:
        return cwd_for(owner)
    except ValueError:
        with task_lock:
            teammate_assignments.pop(owner, None)
        return cwd_for(owner)  # re-derives a fresh lease
Defensive patterns

Strategy: fallback

Validate before calling

from pathlib import Path

def lease_cwd_matches(owner: str) -> bool:
    with task_lock:
        a = teammate_assignments.get(owner) or {}
        try:
            t = load_task(str(a.get('task_id', '')))
            cwd, err = task_worktree_cwd(t)
        except (ValueError, TypeError):
            return False
        return not err and cwd.resolve() == Path(a.get('cwd', '/nonexistent')).resolve()

Try / catch

try:
    cwd = owner_cwd(owner)
except ValueError as exc:
    if 'Assignment cwd changed' in str(exc):
        with task_lock:
            teammate_assignments.pop(owner, None)
        return owner_cwd(owner)  # one re-derivation; if it fails again, surface it
    raise

Prevention

When it happens

Trigger: Deleting and recreating the worktree for the same task at a different path; the worktree name derivation changing between versions; WORKDIR resolution changing so the same worktree resolves to a different absolute path.

Common situations: Cleanup scripts that wipe .worktrees while agents hold assignments; version upgrades that alter worktree naming; workspace relocation under a changing symlink.

Related errors


AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14). Data as JSON: /api/errors/130cafc0e37732bd. Report an issue: GitHub.