github/spec-kit · error · ValueError

manifest.project_root ({manifest.project_root}) does not mat

Error message

manifest.project_root ({manifest.project_root}) does not match project_root ({project_root_resolved})

What it means

Every template-based setup() (this one in the Markdown command path) first cross-checks that the IntegrationManifest's recorded project_root equals project_root.resolve(). The manifest is created at init time with the resolved absolute path of the project; a mismatch means the project directory has moved, been renamed, or is being addressed via a different (e.g. symlinked) path than when it was initialized. Setup refuses to continue to avoid recording manifest entries against the wrong root.

Source

Thrown at src/specify_cli/integrations/base.py:1042

            args.extend(["--model", model])
        if output_json:
            args.extend(["--output-format", "json"])
        return args

    def setup(
        self,
        project_root: Path,
        manifest: IntegrationManifest,
        parsed_options: dict[str, Any] | None = None,
        **opts: Any,
    ) -> list[Path]:
        templates = self.list_command_templates()
        if not templates:
            return []

        project_root_resolved = project_root.resolve()
        if manifest.project_root != project_root_resolved:
            raise ValueError(
                f"manifest.project_root ({manifest.project_root}) does not match "
                f"project_root ({project_root_resolved})"
            )

        dest = self.commands_dest(project_root).resolve()
        try:
            dest.relative_to(project_root_resolved)
        except ValueError as exc:
            raise ValueError(
                f"Integration destination {dest} escapes "
                f"project root {project_root_resolved}"
            ) from exc
        dest.mkdir(parents=True, exist_ok=True)

        script_type = opts.get("script_type", "sh")
        arg_placeholder = (
            self.registrar_config.get("args", "$ARGUMENTS")
            if self.registrar_config

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Always invoke specify from the same canonical project path — the resolved one (if you use a symlink, use it consistently, though resolving is safer).
  2. After moving a project, re-initialize or refresh the manifest (delete .specify/integrations/<key>.manifest.json and re-run the integration setup) so it records the new root.
  3. In CI, pin the checkout directory to a stable absolute path across steps.

Example fix

# before: initialized at /old/path, now run from /new/path
$ cd /new/path && specify ...  # -> mismatch error
# after: re-record the manifest at the new root
$ rm .specify/integrations/<key>.manifest.json && specify ...  # re-run setup
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def manifest_root_matches(project_root: Path, manifest) -> bool:
    return manifest.project_root == project_root.resolve()

Try / catch

try:
    integration.setup(project_root, manifest)
except ValueError as exc:
    if "manifest.project_root" in str(exc):
        # project moved: drop the stale manifest and re-setup at this location
        (project_root / ".specify" / "integrations" / f"{integration.key}.manifest.json").unlink(missing_ok=True)
        integration.setup(project_root, fresh_manifest)
    else:
        raise

Prevention

When it happens

Trigger: Running `specify` commands after mv-ing or cloning the project to a new location; passing a symlinked path to the project on one run and the real path on another; a stale .specify/integrations manifest carried over by copying the project directory.

Common situations: Renaming a workspace folder mid-project; CI checking out to differing absolute paths between the init step and later steps; users following a symlinked home path (~/code vs /Users/name/code) inconsistently.

Related errors


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