{"record":{"id":"534df8781598c1ef","repo":"github/spec-kit","slug":"error-specify-init-dir-does-not-point-to-an-exist","errorCode":null,"errorMessage":"ERROR: SPECIFY_INIT_DIR does not point to an existing directory: {raw}","messagePattern":"ERROR: SPECIFY_INIT_DIR does not point to an existing directory: (.+?)","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/python/common.py","lineNumber":43,"sourceCode":"        parent = current.parent\n        if parent == current:\n            return None\n        current = parent\n\n\ndef resolve_specify_init_dir() -> Path:\n    raw = os.environ.get(\"SPECIFY_INIT_DIR\", \"\")\n    candidate = Path(raw)\n    if not candidate.is_absolute():\n        candidate = Path.cwd() / candidate\n    try:\n        init_root = candidate.resolve(strict=True)\n    except OSError:\n        print(\n            f\"ERROR: SPECIFY_INIT_DIR does not point to an existing directory: {raw}\",\n            file=sys.stderr,\n        )\n        raise SystemExit(1)\n    if not init_root.is_dir():\n        print(\n            f\"ERROR: SPECIFY_INIT_DIR does not point to an existing directory: {raw}\",\n            file=sys.stderr,\n        )\n        raise SystemExit(1)\n    if not (init_root / \".specify\").is_dir():\n        print(\n            \"ERROR: SPECIFY_INIT_DIR is not a Spec Kit project \"\n            f\"(no .specify/ directory): {init_root}\",\n            file=sys.stderr,\n        )\n        raise SystemExit(1)\n    return init_root\n\n\ndef get_repo_root(script_file: Path | None = None) -> Path:\n    if os.environ.get(\"SPECIFY_INIT_DIR\"):","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/scripts/python/common.py#L25-L61","documentation":"In _validate_safe_shared_directory(), an existing component resolves outside the resolved project root. Unlike the symlink checks, this catches non-symlink redirections — junctions, bind mounts, or paths whose canonical location leaves the root once resolved — and refuses to proceed with shared-infra operations through them.","triggerScenarios":"A parent component is a Windows junction, bind mount, or mount point that resolve() relocates outside root; or root was passed non-resolved and a component canonicalizes differently (macOS /tmp, WSL host mounts).","commonSituations":"Windows directory junctions created by mklink /J to save disk; WSL accessing /mnt/c paths; devcontainer bind mounts; project living under symlinked temp dirs.","solutions":["Pass project_path pre-resolved: Path(project).resolve()","Replace junctions/mounts inside the tree with real directories","Move the project to a native filesystem location without redirect semantics","Debug by printing resolve() of each parent vs the root to identify the escaping component"],"exampleFix":"# before\nrun(Path('C:/proj'))  # with a junction inside .specify\n\n# after\nrun(Path('C:/proj').resolve())  # and: rmdir junction, mkdir real dir","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nroot = project_path.resolve()\nfor parent in rel_dir.parents:\n    p = root / parent\n    if p.exists():\n        assert p.resolve().is_relative_to(root), f'{p} escapes root after resolve'","typeGuard":null,"tryCatchPattern":"try:\n    _validate_safe_shared_directory(project_path, directory)\nexcept ValueError as e:\n    if 'escapes project root' in str(e):\n        _validate_safe_shared_directory(Path(project_path).resolve(), directory)\n    else:\n        raise","preventionTips":["Replace Windows junctions/bind mounts inside the tree with real directories","Pass resolved roots; avoid /mnt/c and symlinked temp dirs as project locations","Debug escaping components with a loop printing resolve() per parent"],"tags":["filesystem","symlink","security","portability"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}