zeroclaw-labs/zeroclaw · error · anyhow::Error
Commit message cannot be empty
Error message
Commit message cannot be empty
What it means
The git commit tool extracts the 'message' string from its JSON args and sanitizes it: lines are trim_end'ed, leading and trailing blank lines are dropped, and runs of more than 2 blank lines are collapsed. If nothing survives that sanitization (sanitized.is_empty()), the tool bails with 'Commit message cannot be empty' before ever invoking git. This guard exists because `git commit -m` with an empty message either fails cryptically or, with --allow-empty-message, creates a commit with no subject. Note that a missing 'message' key is a different error ('Missing 'message' parameter'); this one fires only when the key exists but is blank after trimming.
Source
Thrown at crates/zeroclaw-tools/src/git_operations.rs:506
for line in &trimmed_lines {
if line.is_empty() {
consecutive_blanks += 1;
if consecutive_blanks <= 2 {
sanitized_lines.push(line);
}
} else {
consecutive_blanks = 0;
sanitized_lines.push(line);
}
}
// Drop trailing blank lines.
while sanitized_lines.last().is_some_and(|l: &&str| l.is_empty()) {
sanitized_lines.pop();
}
let sanitized = sanitized_lines.join("\n");
if sanitized.is_empty() {
anyhow::bail!("Commit message cannot be empty");
}
// Limit message length
let message = Self::truncate_commit_message(&sanitized);
let output = self
.run_git_command(&["commit", "-m", &message], working_dir)
.await;
match output {
Ok(_) => Ok(ToolResult {
success: true,
output: format!("Committed: {message}").into(),
error: None,
}),
Err(e) => Ok(ToolResult {
success: false,
output: ToolOutput::default(),View on GitHub (pinned to 88bb9c8533)
Solutions
- Supply a non-blank commit message, e.g. {"message": "fix: handle empty stash index"} — a single subject line is enough.
- If the message is built from a variable or template, check it after trimming and substitute a default subject before calling the tool.
- Pre-validate in the caller: reject or re-prompt when message.lines().all(|l| l.trim().is_empty()) so the tool is never invoked with blank input.
- Remember the tool also truncates the message to 2000 chars, so put the important summary on the first line.
Example fix
// before
let args = serde_json::json!({ "message": " \n\n" });
// tool bails: Commit message cannot be empty
// after
let args = serde_json::json!({ "message": "fix: correct stash index handling" }); Defensive patterns
Strategy: validation
Validate before calling
fn build_commit_args(message: &str) -> Option<serde_json::Value> {
let has_content = message.lines().any(|l| !l.trim().is_empty());
has_content.then(|| serde_json::json!({ "message": message }))
} Try / catch
match tool_result {
Err(e) if e.to_string().contains("Commit message cannot be empty") => {
// re-prompt for a subject; never retry with the same blank input
}
other => other,
} Prevention
- Treat a blank commit message as a caller-side bug: assert on it in tests that build commit tool calls.
- When templating messages, coalesce blank render results to a default subject like 'chore: automated change'.
- Log the sanitized message length (not content) before invoking commit so blank input is visible in traces.
When it happens
Trigger: Calling the git tool's commit operation with args like {"message": ""}, {"message": " "}, or {"message": "\n\n\n"}. Any message whose lines are all empty after trim_end (spaces, tabs, bare newlines) reaches the bail at git_operations.rs:506.
Common situations: An LLM agent emits a commit tool call with a placeholder or empty message; a caller templates the message from a variable that is unset and renders to whitespace; a UI forwards an unedited, blank commit dialog; a script chains git_add then git_commit but forgets to pass the message through.
Related errors
- No paths to stage
- Invalid branch specification
- Unknown stash action: {action}. Use: push, pop, list, drop
- Missing 'subcommand' parameter. Use: list, add, remove, prun
- Missing 'worktree_path' parameter for worktree add
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/f7e106c2358672b1.
Report an issue: GitHub.