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

  1. Supply a non-blank commit message, e.g. {"message": "fix: handle empty stash index"} — a single subject line is enough.
  2. If the message is built from a variable or template, check it after trimming and substitute a default subject before calling the tool.
  3. 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.
  4. 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

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


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/f7e106c2358672b1. Report an issue: GitHub.