{"record":{"id":"07e4c4fde5c4a4c0","repo":"github/spec-kit","slug":"manifest-project-root-manifest-project-root-do","errorCode":null,"errorMessage":"manifest.project_root ({manifest.project_root}) does not match project_root ({project_root_resolved})","messagePattern":"manifest\\.project_root \\((.+?)\\) does not match project_root \\((.+?)\\)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/integrations/base.py","lineNumber":1042,"sourceCode":"            args.extend([\"--model\", model])\n        if output_json:\n            args.extend([\"--output-format\", \"json\"])\n        return args\n\n    def setup(\n        self,\n        project_root: Path,\n        manifest: IntegrationManifest,\n        parsed_options: dict[str, Any] | None = None,\n        **opts: Any,\n    ) -> list[Path]:\n        templates = self.list_command_templates()\n        if not templates:\n            return []\n\n        project_root_resolved = project_root.resolve()\n        if manifest.project_root != project_root_resolved:\n            raise ValueError(\n                f\"manifest.project_root ({manifest.project_root}) does not match \"\n                f\"project_root ({project_root_resolved})\"\n            )\n\n        dest = self.commands_dest(project_root).resolve()\n        try:\n            dest.relative_to(project_root_resolved)\n        except ValueError as exc:\n            raise ValueError(\n                f\"Integration destination {dest} escapes \"\n                f\"project root {project_root_resolved}\"\n            ) from exc\n        dest.mkdir(parents=True, exist_ok=True)\n\n        script_type = opts.get(\"script_type\", \"sh\")\n        arg_placeholder = (\n            self.registrar_config.get(\"args\", \"$ARGUMENTS\")\n            if self.registrar_config","sourceCodeStart":1024,"sourceCodeEnd":1060,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/integrations/base.py#L1024-L1060","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Always invoke specify from the same canonical project path — the resolved one (if you use a symlink, use it consistently, though resolving is safer).","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.","In CI, pin the checkout directory to a stable absolute path across steps."],"exampleFix":"# before: initialized at /old/path, now run from /new/path\n$ cd /new/path && specify ...  # -> mismatch error\n# after: re-record the manifest at the new root\n$ rm .specify/integrations/<key>.manifest.json && specify ...  # re-run setup","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef manifest_root_matches(project_root: Path, manifest) -> bool:\n    return manifest.project_root == project_root.resolve()","typeGuard":null,"tryCatchPattern":"try:\n    integration.setup(project_root, manifest)\nexcept ValueError as exc:\n    if \"manifest.project_root\" in str(exc):\n        # project moved: drop the stale manifest and re-setup at this location\n        (project_root / \".specify\" / \"integrations\" / f\"{integration.key}.manifest.json\").unlink(missing_ok=True)\n        integration.setup(project_root, fresh_manifest)\n    else:\n        raise","preventionTips":["Invoke specify from a stable, resolved project path.","After moving a project, delete stale manifests under .specify/integrations/ and re-run setup.","Do not copy .specify manifests between checkouts or machines."],"tags":["integrations","manifest","path-safety","developer-error"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}