nikivdev/code · error

repos root is immutable; use {} or {} or set {}=1 to overrid

Error message

repos root is immutable; use {} or {} or set {}=1 to override

What it means

The repos-root guard in src/repos.rs refuses to operate on a repository root other than the two built-in defaults (DEFAULT_REPOS_ROOT or DEFAULT_CODE_ROOT) unless an explicit override is enabled. This protects users from accidentally cloning, syncing, or mutating repos in an arbitrary directory that may not be managed by this tool.

Source

Thrown at src/repos.rs:1773

    Ok(RepoRef {
        owner: owner.to_string(),
        repo: repo.to_string(),
    })
}

pub(crate) fn normalize_root(raw: &str) -> Result<PathBuf> {
    let expanded = config::expand_path(raw);
    let cwd = std::env::current_dir().context("failed to resolve current directory")?;
    let root = if expanded.is_absolute() {
        expanded
    } else {
        cwd.join(expanded)
    };

    let default_repos_root = config::expand_path(DEFAULT_REPOS_ROOT);
    let default_code_root = config::expand_path(DEFAULT_CODE_ROOT);
    if root != default_repos_root && root != default_code_root && !repos_root_override_enabled() {
        bail!(
            "repos root is immutable; use {} or {} or set {}=1 to override",
            default_repos_root.display(),
            default_code_root.display(),
            REPOS_ROOT_OVERRIDE_ENV
        );
    }

    Ok(root)
}

fn repos_root_override_enabled() -> bool {
    match std::env::var(REPOS_ROOT_OVERRIDE_ENV) {
        Ok(value) => {
            let trimmed = value.trim();
            !trimmed.is_empty() && trimmed != "0"
        }
        Err(_) => false,
    }

View on GitHub (pinned to a747e741ae)

Solutions

  1. Use the default repos root or default code root instead of a custom path
  2. Set the REPOS_ROOT_OVERRIDE_ENV environment variable to 1 to explicitly allow a non-default root
  3. Verify the path is correctly expanded (config::expand_path) and matches one of the two allowed defaults

Example fix

// before
repos_cmd(root: PathBuf::from("/tmp/my-repos"), ...)
// after
export REPOS_ROOT_OVERRIDE=1  # or pass the default root
repos_cmd(root: config::expand_path(DEFAULT_REPOS_ROOT), ...)
Defensive patterns

Strategy: validation

Validate before calling

fn is_allowed_repos_root(root: &Path) -> bool {
    let d = config::expand_path(DEFAULT_REPOS_ROOT);
    let c = config::expand_path(DEFAULT_CODE_ROOT);
    root == d || root == c || std::env::var(REPOS_ROOT_OVERRIDE_ENV).as_deref() == Ok("1")
}
if !is_allowed_repos_root(&root) { eprintln!("root not allowed"); return; }

Try / catch

match do_repos_op(&root) {
    Err(e) if e.to_string().contains("repos root is immutable") => eprintln!("pass the default root or set the override env var"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling a repos command with a custom root path argument that matches neither config::expand_path(DEFAULT_REPOS_ROOT) nor config::expand_path(DEFAULT_CODE_ROOT) while the REPOS_ROOT_OVERRIDE_ENV environment variable is unset.

Common situations: Developers passing --root or a positional path pointing at a scratch/personal directory; CI systems overriding the root without also setting the override env var; expansions of '~' differing from the configured default path.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/9f643b7fc3a84ffc. Report an issue: GitHub.