clockworklabs/SpacetimeDB · error

Path {} is outside repo root {}

Error message

Path {} is outside repo root {}

What it means

Build-time panic in crates/cli/build.rs: `make_repo_root_relative` could not strip the repo-root prefix from a discovered template file, meaning the file's canonical path lies outside the repository root. Embedded template files are stored as repo-relative paths; a path that escapes the root breaks that invariant, so the build panics instead of embedding an unusable path. The usual culprit is a symlink inside templates/ resolving to a location outside the checkout.

Source

Thrown at crates/cli/build.rs:388

/// and transform it into an absolute, canonical path.
fn get_full_path_within_manifest_dir(relative_path: &Path, _manifest_dir: &Path) -> PathBuf {
    let repo_root = get_repo_root();
    let full_path = repo_root.join("templates").join(relative_path);

    full_path.canonicalize().unwrap_or_else(|e| {
        panic!("Failed to canonicalize path {}: {}", full_path.display(), e);
    })
}

/// Transform `full_path` into a relative path within `repo_root`.
///
/// `full_path` and `repo_root` should both be canonical paths, as by [`Path::canonicalize`].
fn make_repo_root_relative(full_path: &Path, repo_root: &Path) -> PathBuf {
    full_path
        .strip_prefix(repo_root)
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|_| {
            panic!(
                "Path {} is outside repo root {}",
                full_path.display(),
                repo_root.display()
            )
        })
}

fn get_git_tracked_files_via_cli(path: &Path, manifest_dir: &Path) -> (Vec<PathBuf>, PathBuf) {
    let repo_root = get_repo_root();
    let repo_root = repo_root.canonicalize().unwrap_or_else(|err| {
        panic!(
            "Failed to canonicalize repo_root path {}: {err:#?}",
            repo_root.display(),
        )
    });

    let resolved_path = make_repo_root_relative(&get_full_path_within_manifest_dir(path, manifest_dir), &repo_root);

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Find escaping links: `find templates -type l -exec readlink -f {} \; | grep -v "^$(pwd)/"` and remove or replace them with real copies.
  2. Keep all embedded template content physically inside the repository.
  3. Re-check the panic's two printed paths — if repo_root itself looks wrong, see the get_repo_root failure (build from the standard checkout layout).
  4. Re-run the build after replacing symlinks with actual files (`cp -L`).

Example fix

# before
ln -s /shared/templates/my-template templates/my-template

# after
cp -r /shared/templates/my-template templates/my-template
git add templates/my-template
Defensive patterns

Strategy: validation

Validate before calling

# Fail if any template path canonicalizes outside the repo root:
root=$(git rev-parse --show-toplevel)
find templates -type l | while read -r l; do
  tgt=$(readlink -f "$l")
  case "$tgt" in "$root"/*) ;; *) echo "escaping symlink: $l -> $tgt";; esac
done

Prevention

When it happens

Trigger: A symlink under templates/ (or repo root) pointing to an absolute path or a directory above the repo root; canonicalization resolving through a symlinked templates directory that actually lives elsewhere; a repo root computed from a moved directory.

Common situations: Developers symlinking shared template folders into their checkout; monorepo tooling that links external assets; building after relocating the repo while stale absolute symlinks remain.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/2dcbe10f9417ab61. Report an issue: GitHub.