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

  1. Commit, stash, or remove unrelated changes before running the doc commit
  2. Restrict the doc command to a clean checkout dedicated to doc updates
  3. 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

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


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