nikivdev/code · error
Refusing to commit internal .ai files
Error message
Refusing to commit internal .ai files
What it means
Before committing, the tool inspects staged files (git diff --cached --name-only) and refuses to commit if any internal .ai working files are staged. These are tool-internal files that should not enter project history. The error lists the offending paths and can be bypassed with FLOW_ALLOW_INTERNAL_COMMIT=1.
Source
Thrown at src/commit.rs:6612
setup::add_gitignore_entry(repo_root, ".ai/internal/")?;
Ok(())
}
fn ensure_no_internal_staged(repo_root: &Path) -> Result<()> {
if env::var("FLOW_ALLOW_INTERNAL_COMMIT").as_deref() == Ok("1") {
return Ok(());
}
let staged = internal_staged_paths(repo_root);
if staged.is_empty() {
return Ok(());
}
println!("Refusing to commit internal .ai files:");
for path in staged {
println!(" - {}", path);
}
println!("Remove these from staging or set FLOW_ALLOW_INTERNAL_COMMIT=1 to override.");
bail!("Refusing to commit internal .ai files");
}
fn internal_staged_paths(repo_root: &Path) -> Vec<String> {
let output = Command::new("git")
.args(["diff", "--cached", "--name-only"])
.current_dir(repo_root)
.output();
let Ok(output) = output else {
return Vec::new();
};
if !output.status.success() {
return Vec::new();
}
let files = String::from_utf8_lossy(&output.stdout);
files
.lines()View on GitHub (pinned to a747e741ae)
Solutions
- Unstage the listed files: `git restore --staged <path>` (or `git rm --cached -r .ai/`)
- Add the .ai directory to .gitignore so it never gets staged
- Run `git add` with explicit paths instead of `git add .`
- Set FLOW_ALLOW_INTERNAL_COMMIT=1 to deliberately override, only if you truly want these files committed
Example fix
// before (shell) git add . && f commit -m "msg" # stages .ai/* too // after (shell) printf '.ai/\n' >> .gitignore && git restore --staged .ai && f commit -m "msg"
Defensive patterns
Strategy: validation
Validate before calling
let staged = Command::new("git")
.args(["diff", "--cached", "--name-only"])
.output()?;
let names = String::from_utf8_lossy(&staged.stdout);
let internal: Vec<&str> = names.lines()
.filter(|p| p.starts_with(".ai/")).collect();
if !internal.is_empty() {
eprintln!("unstage first: {}", internal.join(", "));
} Try / catch
if let Err(e) = tool.commit(msg) {
if e.to_string().contains("internal .ai files") {
let _ = Command::new("git").args(["restore", "--staged", ".ai"]).status();
tool.commit(msg)?;
} else { return Err(e.into()); }
} Prevention
- Never use `git add .`; stage explicit paths
- Keep .ai/ in .gitignore from repo setup
- Review `git status` before running commit tooling
- Only set FLOW_ALLOW_INTERNAL_COMMIT=1 deliberately and temporarily
When it happens
Trigger: Running `f commit` while internal .ai files (e.g. commit queue/review state under .ai/) are in the git staging area, as detected by internal_staged_paths().
Common situations: User ran `git add .` or `git add -A` after the tool wrote its internal state files, .gitignore is missing entries for the .ai directory, or a previous crashed run left state files behind that then got staged.
Related errors
- git add failed with {}
- Refusing to commit generated files
- git add -- <paths> failed with status {}
- {} exists but is not a git repo: {}
- jj git export retry loop should always return
AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01).
Data as JSON: /api/errors/39727277c8caea12.
Report an issue: GitHub.