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
- Use the default repos root or default code root instead of a custom path
- Set the REPOS_ROOT_OVERRIDE_ENV environment variable to 1 to explicitly allow a non-default root
- 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
- Always derive the root from config::expand_path(DEFAULT_*) instead of hardcoding paths
- Set REPOS_ROOT_OVERRIDE_ENV=1 only in throwaway/dev environments
- Document the allowed roots in your CI scripts
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
- No prompt provided. Usage: f agents run {} "your prompt here
- expected [{}] to be a table in global flow config
- agent run requires a non-empty query
- empty resolver command for {}
- prompt is empty
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/9f643b7fc3a84ffc.
Report an issue: GitHub.