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 GenericIntegration.setup() (src/specify_cli/integrations/generic/__init__.py:115) when the IntegrationManifest was created against a different root than the resolved project_root argument. Like the copilot/forge/hermes setups, generic setup verifies manifest.project_root == project_root.resolve() before any writes, binding each manifest to exactly one project location.
Source
Thrown at src/specify_cli/integrations/generic/__init__.py:115
)
def setup(
self,
project_root: Path,
manifest: IntegrationManifest,
parsed_options: dict[str, Any] | None = None,
**opts: Any,
) -> list[Path]:
"""Install commands to the user-provided commands directory."""
commands_dir = self._resolve_commands_dir(parsed_options, opts)
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 = (project_root / commands_dir).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 = "$ARGUMENTS"
created: list[Path] = []
View on GitHub (pinned to bf88c9f9a8)
Solutions
- Build the manifest with the same resolved root passed to setup: IntegrationManifest(project_root=project_root.resolve()).
- Resolve project_root once and reuse that Path for both the manifest and the setup call.
- Use the CLI path (specify init --integration generic --integration-options="--commands-dir ...") which handles manifest creation.
Example fix
# before
manifest = IntegrationManifest(project_root=Path("proj"))
GenericIntegration().setup(Path("/abs/proj"), manifest, parsed_options={"commands_dir": "x"})
# after
root = Path("/abs/proj").resolve()
manifest = IntegrationManifest(project_root=root)
GenericIntegration().setup(root, manifest, parsed_options={"commands_dir": "x"}) Defensive patterns
Strategy: validation
Validate before calling
root = project_root.resolve()
if manifest.project_root != root:
manifest = IntegrationManifest(project_root=root) Try / catch
try:
integration.setup(root, manifest, parsed_options=opts)
except ValueError as e:
if "manifest.project_root" in str(e):
manifest = IntegrationManifest(project_root=root.resolve())
integration.setup(root, manifest, parsed_options=opts)
else:
raise Prevention
- One resolved root, one manifest — create both from the same Path.resolve().
- Don't reuse manifests from fixtures or other projects.
- Prefer the specify CLI, which constructs manifests correctly.
When it happens
Trigger: GenericIntegration().setup(root, manifest) with manifest built from a different directory or an unresolved path variant (symlink differences) — the strict equality on resolved paths fails.
Common situations: Manual/programmatic use of the generic integration where the manifest comes from a fixture or another project; macOS /tmp vs /private/tmp; passing a relative project_root while the manifest recorded an absolute one.
Related errors
- manifest.project_root ({manifest.project_root}) does not mat
- manifest.project_root ({manifest.project_root}) does not mat
- manifest.project_root ({manifest.project_root}) does not mat
- Integration destination {dest_resolved} escapes project root
- Integration destination {dest} escapes project root {project
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/fba53a777b819709.
Report an issue: GitHub.