github/spec-kit · error · SystemExit

Error: --short-name requires a value

Error message

Error: --short-name requires a value

What it means

_ensure_safe_shared_directory() walks each component of the shared-infrastructure directory relative to the project root and refuses to traverse a component that is a symlink. This is a defense against symlink attacks: even a symlink that points back inside the project could be swapped, so the walk fails closed with SymlinkedSharedPathError (a ValueError subclass) before any directory is created or written into.

Source

Thrown at extensions/git/scripts/python/create_new_feature_branch.py:104

    use_timestamp: bool = False
    description_parts: list[str] = field(default_factory=list)


def parse_args(argv: list[str]) -> Args:
    args = Args()
    i = 0
    while i < len(argv):
        arg = argv[i]
        if arg == "--json":
            args.json_mode = True
        elif arg == "--dry-run":
            args.dry_run = True
        elif arg == "--allow-existing-branch":
            args.allow_existing = True
        elif arg == "--short-name":
            if i + 1 >= len(argv) or argv[i + 1].startswith("--"):
                _err("Error: --short-name requires a value")
                raise SystemExit(1)
            i += 1
            args.short_name = argv[i]
        elif arg == "--number":
            if i + 1 >= len(argv) or argv[i + 1].startswith("--"):
                _err("Error: --number requires a value")
                raise SystemExit(1)
            i += 1
            args.branch_number = argv[i]
            if not re.fullmatch(r"[0-9]+", args.branch_number):
                _err("Error: --number must be a non-negative integer")
                raise SystemExit(1)
        elif arg == "--timestamp":
            args.use_timestamp = True
        elif arg in ("--help", "-h"):
            print(HELP_TEXT)
            raise SystemExit(0)
        else:
            args.description_parts.append(arg)

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Replace the symlinked directory with a real directory and copy the contents in (or use cp -aL to dereference)
  2. If sharing between projects is the goal, use a supported mechanism (e.g. presets or a package) instead of symlinking inside the tree
  3. Remove the stale symlink: rm .specify/shared (it is a link, not the data) and let the CLI recreate the directory
  4. Check for symlinks before invoking: p.is_symlink() for each parent component of the destination

Example fix

# before: .specify/shared -> /home/me/dotfiles/shared
$ specify init  # raises SymlinkedSharedPathError

# after
$ rm .specify/shared && cp -a /home/me/dotfiles/shared .specify/shared
$ specify init  # ok
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def parents_are_real_dirs(project: Path, rel_dir: Path) -> bool:
    cur = project
    for part in rel_dir.parts:
        cur = cur / part
        if cur.is_symlink():
            return False
    return True

assert parents_are_real_dirs(project_path, rel_dir)

Try / catch

from specify_cli.shared_infra import SymlinkedSharedPathError

try:
    _ensure_safe_shared_directory(project_path, directory)
except SymlinkedSharedPathError as e:
    print(f'found symlinked component: {e}; replace links with real dirs')
    raise

Prevention

When it happens

Trigger: Any shared-infra write where an intermediate directory under project_path (e.g. .specify, .specify/shared, .specify/shared/scripts) is a symlink — commonly a developer symlinking .specify/shared to a dotfiles repo or another checkout to 'share' infra between projects.

Common situations: Symlinking .specify to a central folder to reuse specs across clones; monorepo setups where shared tooling is a symlink to packages/shared; restoring a project from a backup tool that recreates directories as links; CI caches that materialize paths as symlinks.

Related errors


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/04f7099d363f0f5b. Report an issue: GitHub.