nikivdev/code · error
refusing doc commit because unrelated changes are present: {
Error message
refusing doc commit because unrelated changes are present: {} What it means
Before committing documentation changes the library snapshots the git working tree and allows only a whitelisted set of paths (the doc files it manages). If any other modified/untracked file is present, the whole doc commit is refused so unrelated work is never swept into the commit.
Source
Thrown at src/codex_session_docs.rs:575
}
let mut allowed_paths = BTreeSet::new();
let mut session_keys = Vec::new();
for index in &candidate_indexes {
let entry = &entries[*index];
session_keys.push(entry.session_key.clone());
for path in allowed_commit_paths(project_root, entry) {
allowed_paths.insert(path);
}
}
let unexpected = changed_paths
.iter()
.filter(|path| !allowed_paths.contains(path.as_str()))
.cloned()
.collect::<Vec<_>>();
if !unexpected.is_empty() {
bail!(
"refusing doc commit because unrelated changes are present: {}",
unexpected.join(", ")
);
}
let files = changed_paths
.into_iter()
.filter(|path| allowed_paths.contains(path.as_str()))
.collect::<Vec<_>>();
if files.is_empty() {
return Ok(None);
}
let commit_message = build_doc_commit_message(&entries, &candidate_indexes);
let plan = CommitPendingPlan {
session_keys: session_keys.clone(),
files: files.clone(),
commit_message: commit_message.clone(),View on GitHub (pinned to a747e741ae)
Solutions
- Commit, stash, or remove unrelated changes before running the doc commit
- Restrict the doc command to a clean checkout dedicated to doc updates
- Compare against `git status --porcelain` to identify and clean the offending paths
Example fix
// before
run_doc_commit(); // fails when repo is dirty with unrelated files
// after
let unexpected: Vec<_> = changed_paths.iter().filter(|p| !ALLOWED.contains(&p.as_str())).collect();
if unexpected.is_empty() {
run_doc_commit();
} else {
eprintln!("clean or commit these first: {:?}", unexpected);
} Defensive patterns
Strategy: validation
Validate before calling
let status = Command::new("git").args(["status", "--porcelain", "--untracked-files=all"]).output()?;
let changed: Vec<&str> = String::from_utf8_lossy(&status.stdout).lines().filter_map(|l| l.get(3..)).collect();
let unexpected: Vec<_> = changed.iter().filter(|p| !ALLOWED_PATHS.contains(p)).collect();
if !unexpected.is_empty() {
anyhow::bail!("clean unrelated changes first: {:?}", unexpected);
} Type guard
fn tree_is_clean_for_paths(changed: &[String], allowed: &[&str]) -> bool {
changed.iter().all(|p| allowed.contains(&p.as_str()))
} Try / catch
match commit_docs() {
Err(e) if e.to_string().starts_with("refusing doc commit") => {
eprintln!("{}\nstash/commit unrelated work, then retry", e);
}
other => other?,
} Prevention
- Run doc commits from a clean working tree or a dedicated checkout
- Add scratch/artifact paths to .gitignore so untracked files never appear
- Avoid mixing manual edits with automated doc promotion in the same tree
When it happens
Trigger: Invoking the doc commit path while `git status --porcelain` shows changed paths outside `allowed_paths` — e.g. hand-edited source files, build artifacts, or unrelated untracked files in the repo.
Common situations: Developers promoting docs mid-feature with dirty working trees; leftover untracked scratch files; CI runners that checked out a tree with local modifications.
Related errors
- git commit failed with {}
- failed to resolve HEAD commit after quick commit
- Refusing to remove non-Flow hook at {}.
- Failed to stash local changes: {}. Resolve the issue and re-
- jj git export retry loop should always return
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/e0f17824d504bbb2.
Report an issue: GitHub.