can1357/oh-my-pi · error · ValueError
invalid branch slug {slug!r}: expected kebab-case [a-z0-9-],
Error message
invalid branch slug {slug!r}: expected kebab-case [a-z0-9-], 1-50 chars, no leading/trailing/double hyphen What it means
ValueError raised by validate_branch_slug when a branch slug is not valid kebab-case: it must be a string of 1-50 chars matching [a-z0-9-], with no leading/trailing hyphen and no double hyphen. It guards sandbox/workspace branch creation (execute) and branch renames (rename_workspace_branch) from producing invalid git branch names.
Source
Thrown at python/robomp/src/sandbox.py:154
env["GIT_TERMINAL_PROMPT"] = "0"
return env
def make_branch(*, issue_number: int, title: str, seed: str | None = None) -> str:
return f"farm/{_short_hex(seed or f'{issue_number}-{title}')}/{_slug(title or f'issue-{issue_number}')}"
_BRANCH_SLUG_RE = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
def validate_branch_slug(slug: object) -> str:
"""Return ``slug`` if it is a valid kebab-case branch slug, else raise.
Rules: 1-50 chars, only ``[a-z0-9-]``, no leading/trailing hyphen, no
double hyphen. Raises ``ValueError`` otherwise.
"""
if not isinstance(slug, str) or not _BRANCH_SLUG_RE.fullmatch(slug) or len(slug) > 50:
raise ValueError(
f"invalid branch slug {slug!r}: expected kebab-case [a-z0-9-], 1-50 chars, no leading/trailing/double hyphen"
)
return slug
def rename_workspace_branch(
workspace: Workspace,
new_slug: str,
*,
pr_number: int | None = None,
slot_uid: int | None = None,
) -> str:
"""Rename the workspace's local branch to ``farm/<hex>/<new_slug>``.
The 8-hex disambiguator stays untouched; only the trailing slug after
the second `/` changes. Runs ``git branch -m`` inside the worktree
(which updates the shared refs in the pool) and mutates
``workspace.branch`` in place.View on GitHub (pinned to 9690622007)
Solutions
- Normalize the input before calling: lowercase, replace non-[a-z0-9] runs with '-', collapse '--' to '-', strip leading/trailing '-', and truncate to 50 chars.
- Check the exact invalid value in the error message (it is repr-quoted) to spot the offending characters.
- If the slug comes from config/env, fix the configured value to kebab-case.
- If the slug is derived from user/ticket input, call validate_branch_slug yourself first and sanitize on failure.
Example fix
# before
slug = f"feature/{ticket.title}" # e.g. 'feature/Fix Login Flow!'
sandbox.execute(action, branch=slug) # ValueError
# after
import re
def to_slug(s: str) -> str:
s = re.sub(r"[^a-z0-9-]+", "-", s.lower()).strip("-")
s = re.sub(r"-{2,}", "-", s)
return s[:50].strip("-") or "branch"
sandbox.execute(action, branch=to_slug(ticket.title)) Defensive patterns
Strategy: validation
Validate before calling
import re
_BRANCH_SLUG_RE = re.compile(r"[a-z0-9]+(-[a-z0-9]+)*")
def safe_slug(raw: str) -> str:
s = re.sub(r"[^a-z0-9-]+", "-", raw.lower()).strip("-")
s = re.sub(r"-{2,}", "-", s)[:50].strip("-")
if not s or not _BRANCH_SLUG_RE.fullmatch(s) or len(s) > 50:
raise ValueError(f"cannot sanitize slug from {raw!r}")
return s Type guard
import re
_BRANCH_SLUG_RE = re.compile(r"[a-z0-9]+(-[a-z0-9]+)*")
def is_valid_branch_slug(slug: object) -> bool:
return isinstance(slug, str) and bool(_BRANCH_SLUG_RE.fullmatch(slug)) and len(slug) <= 50 Try / catch
try:
slug = validate_branch_slug(candidate)
except ValueError as e:
slug = sanitize_to_slug(candidate) # lowercase, non-alnum -> '-', collapse/truncate
validate_branch_slug(slug) Prevention
- Always sanitize derived names (titles, tickets, repo names) through a kebab-case normalizer before validate_branch_slug.
- Strip '#' and '/' prefixes from issue/repo references — they are not legal in slugs.
- Truncate to 50 chars after joining parts, then re-strip trailing hyphens.
- Add a unit test that every slug your pipeline generates passes validate_branch_slug.
When it happens
Trigger: Passing a slug containing uppercase letters, underscores, spaces, dots, or slashes; an empty string; a string over 50 chars; a slug starting/ending with '-'; or one containing '--'. Also raised when a non-string (None, int) reaches the validator.
Common situations: Deriving a slug from a task title or ticket name without normalizing (spaces/underscores/uppercase left in); interpolating an issue number prefix like '#123' or a repo name with '/'; truncating a long title to over 50 chars including separators; passing None when the branch name is missing from config.
Related errors
- local branch ${localBranch} does not exist
- reference not found: {name}
- Invalid skill name "${raw}". Use lowercase letters, digits,
- Unknown tool${unknown.length === 1 ? "" : "s"} in --tools: $
- Unknown OAuth provider '${providerArg}'. Known: ${providers
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8f210ca6c7b7c77f.
Report an issue: GitHub.