gitbutlerapp/gitbutler · error · anyhow::Error

line {line_number}: pick does not accept a message clause

Error message

line {line_number}: pick does not accept a message clause

What it means

Raised by `parse_integration_steps_script` (parsing.rs) when a script line starts with `pick` but also contains a `| message=...` clause. Only `squash` accepts a message clause; `pick` has no message of its own. The line number in the message is 1-based within the edited script.

Source

Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs:45

        let line_number = line_number + 1;
        let line = line.to_str_lossy();
        let trimmed = line.trim();
        if trimmed.is_empty() || trimmed.starts_with('#') {
            continue;
        }

        let (command_part, message_part) = split_message_clause(trimmed)
            .with_context(|| format!("line {line_number}: invalid message clause"))?;
        let tokens = command_part.split_whitespace().collect::<Vec<_>>();
        let Some(command) = tokens.first().copied() else {
            continue;
        };
        let arguments = tokens.get(1..).unwrap_or_default();

        let step = match command {
            "pick" => {
                if message_part.is_some() {
                    bail!("line {line_number}: pick does not accept a message clause");
                }
                if arguments.len() != 1 {
                    bail!("line {line_number}: pick requires exactly one commit");
                }
                let commit = arguments
                    .first()
                    .copied()
                    .expect("validated pick arity above");
                InteractiveIntegrationStep::Pick {
                    commit_id: resolve_commit(commit, &allowed_commits).map_err(|err| {
                        anyhow::anyhow!("line {line_number}: invalid pick commit: {err}")
                    })?,
                }
            }
            "merge" => {
                if message_part.is_some() {
                    bail!("line {line_number}: merge does not accept a message clause");
                }

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Remove the `| message=...` clause from the pick line: `pick 4f2a9c1`.
  2. If you want pick + different message, use a `squash` step with a single intent or adjust the plan upstream — the grammar only supports messages on squash.
  3. Check the script against `render_integration_steps_script` output for the canonical format before submitting.

Example fix

# before
pick 4f2a9c1 | message="new message"

# after
pick 4f2a9c1
Defensive patterns

Strategy: validation

Validate before calling

// Dry-run the script through the parser before applying:
let steps = but_workspace::branch::integrate_branch_upstream::parse_integration_steps_script(&script, &divergence)
    .map_err(|e| user_friendly(e))?; // surfaces 'line N: pick does not accept a message clause'

Try / catch

match parse_integration_steps_script(&script, &divergence) {
    Ok(steps) => { /* proceed to integrate_branch_with_steps */ }
    Err(err) => show_editor_error(err.to_string()), // errors carry 'line N:' context already
}

Prevention

When it happens

Trigger: Script line like `pick 4f2a9c1 | message="fix"` — `split_message_clause` splits on the first `|`, so pick sees a Some(message_part) and bails. Any attempt to reword while picking hits this.

Common situations: Users familiar with git rebase's `reword`/`pick <sha> <subject>` syntax try to attach a message to pick; or a UI round-trips a squash line into a pick line but keeps the message clause.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/4b62399d329db3b2. Report an issue: GitHub.