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

Raised by CopilotIntegration._setup_commands() (src/specify_cli/integrations/copilot/__init__.py:493) when the IntegrationManifest passed to setup() was constructed against a different project root than the one given to the call (compared after Path.resolve()). The manifest records project_root at creation, and every setup path verifies the caller is still operating in that same project to prevent cross-project writes.

Source

Thrown at src/specify_cli/integrations/copilot/__init__.py:493

        # Install agent runtime events
        event_files = self.emit_events(
            project_root, manifest, events=opts.get("events"), parsed_options=parsed_options
        )
        created.extend(event_files)
        return created

    def _setup_commands(
        self,
        project_root: Path,
        manifest: IntegrationManifest,
        parsed_options: dict[str, Any] | None = None,
        **opts: Any,
    ) -> list[Path]:
        """Commands mode: .agent.md + .prompt.md + VS Code settings merge."""
        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})"
            )

        templates = self.list_command_templates()
        if not templates:
            return []

        from ...presets import PresetResolver

        preset_resolver = PresetResolver(project_root_resolved)

        dest = self.commands_dest(project_root)
        dest_resolved = dest.resolve()
        try:
            dest_resolved.relative_to(project_root_resolved)
        except ValueError as exc:
            raise ValueError(

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Construct the IntegrationManifest with the exact same project_root (resolved the same way) that you pass to setup().
  2. Use project_root.resolve() consistently at both construction and call sites.
  3. Do not reuse a manifest across projects — create a fresh manifest per project.
  4. If invoking the CLI, re-run 'specify init' from the project directory instead of calling setup() manually.

Example fix

# before
manifest = IntegrationManifest(project_root=Path("/tmp/proj"))
integration.setup(Path("/private/tmp/proj"), manifest)

# after
root = Path("/tmp/proj").resolve()
manifest = IntegrationManifest(project_root=root)
integration.setup(root, manifest)
Defensive patterns

Strategy: validation

Validate before calling

root = project_root.resolve()
assert manifest.project_root == root, (
    f"manifest {manifest.project_root} != root {root}"
)

Try / catch

try:
    integration.setup(root, manifest)
except ValueError as e:
    if "does not match" in str(e):
        manifest = IntegrationManifest(project_root=root.resolve())
        integration.setup(root, manifest)
    else:
        raise

Prevention

When it happens

Trigger: Calling integration.setup(project_root, manifest) with a manifest built via IntegrationManifest(other_root) — e.g. manifest created for the resolved cwd but setup invoked with a symlinked or differently-spelled path, or a manifest reused across two projects.

Common situations: Programmatically driving setup() and creating the manifest in one directory then calling setup with another; macOS /tmp vs /private/tmp symlink mismatches after resolve(); reusing a cached manifest object after the process changed directories.

Related errors


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