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

Invalid worktree name. Use 1-40 chars: letters, numbers, .,

Error message

Invalid worktree name. Use 1-40 chars: letters, numbers, ., _, -

What it means

Thrown by WorktreeManager._validate_name when creating a worktree whose name fails the regex [A-Za-z0-9._-]{1,40}. The name is used both as a directory name under the worktree dir and inside the branch name wt/{name}, so any character outside that whitelist (spaces, slashes, unicode) or a name longer than 40 chars (or empty/None) is rejected before any git command runs. This is a fail-fast input validation guard, not a git failure.

Source

Thrown at agents/s12_worktree_task_isolation.py:280

            raise RuntimeError(msg or f"git {' '.join(args)} failed")
        return (r.stdout + r.stderr).strip() or "(no output)"

    def _load_index(self) -> dict:
        return json.loads(self.index_path.read_text())

    def _save_index(self, data: dict):
        self.index_path.write_text(json.dumps(data, indent=2))

    def _find(self, name: str) -> dict | None:
        idx = self._load_index()
        for wt in idx.get("worktrees", []):
            if wt.get("name") == name:
                return wt
        return None

    def _validate_name(self, name: str):
        if not re.fullmatch(r"[A-Za-z0-9._-]{1,40}", name or ""):
            raise ValueError(
                "Invalid worktree name. Use 1-40 chars: letters, numbers, ., _, -"
            )

    def create(self, name: str, task_id: int = None, base_ref: str = "HEAD") -> str:
        self._validate_name(name)
        if self._find(name):
            raise ValueError(f"Worktree '{name}' already exists in index")
        if task_id is not None and not self.tasks.exists(task_id):
            raise ValueError(f"Task {task_id} not found")

        path = self.dir / name
        branch = f"wt/{name}"
        self.events.emit(
            "worktree.create.before",
            task={"id": task_id} if task_id is not None else {},
            worktree={"name": name, "base_ref": base_ref},
        )
        try:

View on GitHub (pinned to 985456f4ad)

Solutions

  1. Sanitize the name before calling create(): lower-case it and re.sub(r'[^A-Za-z0-9._-]+', '-', name), then trim to 40 chars
  2. Strip whitespace around the name and reject empty results before calling the manager
  3. Replace '/' in derived names (e.g. from branch paths) with '-' so the wt/{name} branch stays well-formed
  4. Catch ValueError at the tool boundary and surface it back to the caller so the agent can retry with a cleaned name

Example fix

// before
wt.create(name="Fix login bug / session", task_id=7)
// after
import re
name = re.sub(r'[^A-Za-z0-9._-]+', '-', "Fix login bug / session").strip('-.')[:40]
wt.create(name=name, task_id=7)
Defensive patterns

Strategy: validation

Validate before calling

import re

def valid_worktree_name(name: str) -> bool:
    return bool(re.fullmatch(r"[A-Za-z0-9._-]{1,40}", name or ""))

# before create():
assert valid_worktree_name(name), "name must be 1-40 chars of [A-Za-z0-9._-]"

Type guard

def is_valid_worktree_name(name: object) -> bool:
    return isinstance(name, str) and bool(__import__('re').fullmatch(r"[A-Za-z0-9._-]{1,40}", name))

Try / catch

try:
    path = wt.create(name, task_id=tid)
except ValueError as e:
    if 'Invalid worktree name' in str(e):
        name = re.sub(r'[^A-Za-z0-9._-]+', '-', name).strip('-.')[:40]
        path = wt.create(name, task_id=tid)
    else:
        raise

Prevention

When it happens

Trigger: Calling worktree create with name="my task" (space), name="feature/fix" (slash), name="задача" (unicode), name="" or None, or a name of 41+ characters. The regex uses fullmatch, so even a trailing newline embedded in the string fails.

Common situations: Agent pipelines auto-deriving worktree names from free-form task subjects or ticket titles without sanitizing; names containing '/' that would also collide with the wt/{name} branch namespace; trailing whitespace from user input not being stripped before the call.

Related errors


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