github/spec-kit · error · ValueError

Absolute paths are not allowed in manifests: {rel}

Error message

Absolute paths are not allowed in manifests: {rel}

What it means

Raised by _validate_rel_path() in manifest.py (src/specify_cli/integrations/manifest.py:36) when a manifest operation is given a relative path that is actually absolute. Manifests record every installed file as a path relative to the project root (hashed and removed on uninstall), so absolute paths — which could target anything on disk — are rejected before any filesystem write.

Source

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


def _sha256(path: Path) -> str:
    """Return the hex SHA-256 digest of *path*."""
    h = hashlib.sha256()
    with open(path, "rb") as fh:
        for chunk in iter(lambda: fh.read(8192), b""):
            h.update(chunk)
    return h.hexdigest()


def _validate_rel_path(rel: Path, root: Path) -> Path:
    """Resolve *rel* against *root* and verify it stays within *root*.

    Raises ``ValueError`` if *rel* is absolute, contains ``..`` segments
    that escape *root*, or otherwise resolves outside the project root.
    """
    if rel.is_absolute():
        raise ValueError(
            f"Absolute paths are not allowed in manifests: {rel}"
        )
    resolved = (root / rel).resolve()
    root_resolved = root.resolve()
    try:
        resolved.relative_to(root_resolved)
    except ValueError:
        raise ValueError(
            f"Path {rel} resolves to {resolved} which is outside "
            f"the project root {root_resolved}"
        ) from None
    return resolved


def _manifest_path_label(root: Path, path: Path) -> str:
    try:
        return path.relative_to(root).as_posix()
    except ValueError:

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Convert the path to be relative to project_root before recording: path.relative_to(project_root).
  2. In custom setup() implementations, record the destination relative path ('folder/commands/plan.md'), never the resolved absolute one.
  3. Check for accidental leading '/' or drive letters in path construction.

Example fix

# before
created = dest / "plan.md"          # absolute
manifest.record_file(str(created), content)

# after
rel = created.relative_to(project_root)
manifest.record_file(rel.as_posix(), content)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def to_manifest_rel(path: Path, root: Path) -> Path:
    if path.is_absolute():
        return path.relative_to(root)  # raises if outside root
    return path

rel = to_manifest_rel(created_file, project_root)
manifest.record_file(rel.as_posix(), content)

Type guard

def is_relative_path(p) -> bool:
    return not Path(p).is_absolute() and ".." not in Path(p).parts

Try / catch

try:
    manifest.record_file(rel_str, content)
except ValueError as e:
    if "Absolute paths" in str(e):
        rel_str = Path(rel_str).relative_to(project_root).as_posix()
        manifest.record_file(rel_str, content)
    else:
        raise

Prevention

When it happens

Trigger: Calling manifest.record_file()/record_existing() (or any code path reaching _validate_rel_path) with a Path like Path('/etc/passwd') or an absolute Windows path 'C:\\x\\y' — rel.is_absolute() is true and ValueError is raised immediately.

Common situations: Custom integration setup() code building file paths from absolute sources (resolved template paths) and passing them straight to manifest.record_file(); passing dest-resolved paths instead of project-relative ones; Windows callers using rooted paths.

Related errors


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