xai-org/grok-build · error
Working tree is dirty. Commit changes first, or use --force.
Error message
Working tree is dirty. Commit changes first, or use --force.
What it means
Before creating a tag, `grok plugin tag` runs `git status --porcelain` in the plugin directory; if output is non-empty the working tree is dirty and the command bails, unless --force is passed. This prevents tagging uncommitted state.
Source
Thrown at crates/codegen/xai-grok-pager/src/plugin_cmd.rs:742
Ok(ManifestLoadResult::NotFound) => bail!("No plugin.json found in {path}."),
Err(e) => bail!("Failed to load manifest: {e}"),
};
let tag = format!(
"v{}",
version
.strip_prefix('v')
.or_else(|| version.strip_prefix('V'))
.unwrap_or(&version)
);
if !force {
let out = std::process::Command::new("git")
.args(["status", "--porcelain"])
.current_dir(&root)
.output()?;
if !out.stdout.is_empty() {
bail!("Working tree is dirty. Commit changes first, or use --force.");
}
}
if dry_run {
println!("Would create tag: {tag}");
if push {
println!("Would push tag to remote.");
}
return Ok(());
}
let mut cmd = std::process::Command::new("git");
cmd.args(["tag", &tag]);
if force {
cmd.arg("--force");
}
let out = cmd.current_dir(&root).output()?;
if !out.status.success() {View on GitHub (pinned to bc7f02eddd)
Solutions
- Commit or stash your changes, then re-run the tag command
- Re-run with `--force` to tag anyway
- Add untracked generated files to .gitignore so porcelain output is clean
Example fix
// before grok plugin tag . // after (either) git add -A && git commit -m "release 1.0.0" grok plugin tag . // or grok plugin tag . --force
Defensive patterns
Strategy: validation
Validate before calling
fn worktree_clean(root: &std::path::Path) -> bool {
std::process::Command::new("git")
.args(["status", "--porcelain"])
.current_dir(root)
.output()
.map(|o| o.stdout.is_empty())
.unwrap_or(false)
}
// if !worktree_clean(&root) { commit/stash or pass --force } Type guard
fn is_clean_repo(root: &std::path::Path) -> bool {
root.join(".git").exists()
&& std::process::Command::new("git")
.args(["status", "--porcelain"])
.current_dir(root)
.output()
.map(|o| o.status.success() && o.stdout.is_empty())
.unwrap_or(false)
} Try / catch
match cmd_tag(dir, false, false, false) {
Err(e) if e.to_string().contains("Working tree is dirty") => {
eprintln!("Commit changes or re-run with --force");
}
Ok(_) => {}
Err(e) => return Err(e),
} Prevention
- Commit or stash before tagging; never tag uncommitted work
- Add generated files to .gitignore so status stays clean
- Run `git status --porcelain` as a preflight in release scripts
When it happens
Trigger: Running `grok plugin tag <dir>` without --force while the git repo in <dir> has uncommitted or untracked changes.
Common situations: Edited plugin files but forgot to commit; untracked generated files showing in porcelain; mid-development tagging attempt.
Related errors
- Failed to create tag: {stderr}
- {e}
- Failed to load manifest: {e}
- No plugin.json found in {path}.
- working tree has uncommitted changes; commit or stash before
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/39cc75fda376ae33.
Report an issue: GitHub.