github/spec-kit · error · ValueError

Integration manifest directory path is not a directory: {lab

Error message

Integration manifest directory path is not a directory: {label}

What it means

Raised while creating the manifest directory chain when an existing path component is present but is a regular file, not a directory. The CLI cannot mkdir over a file, so it aborts rather than clobbering it.

Source

Thrown at src/specify_cli/integrations/manifest.py:75

def _ensure_safe_manifest_directory(root: Path, directory: Path) -> None:
    """Create a manifest directory without following symlinked parents."""
    root_resolved = root.resolve()
    try:
        rel = directory.relative_to(root)
    except ValueError:
        label = _manifest_path_label(root, directory)
        raise ValueError(f"Integration manifest directory escapes project root: {label}") from None

    current = root
    for part in rel.parts:
        current = current / part
        label = _manifest_path_label(root, current)
        if current.is_symlink():
            raise ValueError(f"Refusing to use symlinked integration manifest directory: {label}")
        if current.exists():
            if not current.is_dir():
                raise ValueError(f"Integration manifest directory path is not a directory: {label}")
            try:
                current.resolve().relative_to(root_resolved)
            except (OSError, ValueError):
                raise ValueError(f"Integration manifest directory escapes project root: {label}") from None
            continue
        current.mkdir()
        try:
            current.resolve().relative_to(root_resolved)
        except (OSError, ValueError):
            raise ValueError(f"Integration manifest directory escapes project root: {label}") from None


def _ensure_safe_manifest_destination(root: Path, path: Path) -> None:
    """Refuse manifest writes that would escape the project or follow symlinks."""
    root_resolved = root.resolve()
    _ensure_safe_manifest_directory(root, path.parent)
    label = _manifest_path_label(root, path)
    if path.is_symlink():

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Inspect the offending component printed in the label (e.g. ls -la .specify) and identify what created it
  2. If it is a stray file, delete or rename it, then re-run specify integration install/init
  3. If it is legitimate config, relocate it so the path can be a directory

Example fix

# before
-rw-r--r-- .specify        # stray file blocks save()
# after
rm .specify && mkdir -p .specify/integrations
Defensive patterns

Strategy: validation

Validate before calling

def dir_chain_clear(root: Path, directory: Path) -> bool:
    cur = root
    for part in directory.relative_to(root).parts:
        cur = cur / part
        if cur.exists() and not cur.is_dir():
            return False
    return True

Try / catch

try:
    manifest.save()
except ValueError as exc:
    if "not a directory" in str(exc):
        remove_blocking_file_and_retry()
    else:
        raise

Prevention

When it happens

Trigger: A file named .specify or .specify/integrations exists in the project when IntegrationManifest.save() tries to ensure the directory chain (e.g. someone created a .specify marker file, or a template rendered a file where a directory belongs).

Common situations: A stray file named .specify committed by a scaffolding tool or editor plugin; Case-insensitive filesystem collisions (e.g. a file named 'Integrations' vs the integrations dir); Partial/corrupted prior installs that left a file in the directory position

Related errors


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