gitbutlerapp/gitbutler · error

No trailers found on snapshot commit message

Error message

No trailers found on snapshot commit message

What it means

The FromStr impl for a snapshot commit parses the message into title, body, and a final trailer block. If the message has no section after the last empty-line split — i.e. no trailers — split.pop() yields None and this error is thrown. Snapshot commits are expected to always carry trailers (oplog metadata).

Solutions

  1. Use only oplog snapshot commits that were created by the tool (trailers intact).
  2. If trailers were lost, the commit cannot be interpreted as a snapshot — recreate the snapshot operation.
  3. Guard parsing: check the message for a trailer section (e.g. contains a known trailer key) before calling from_str.
  4. Check for older-format snapshots and migrate them instead of parsing directly.

Example fix

// before
let entry = OplogEntry::from_str(&message)?; // panics/errors without trailers
// after
if !message.contains("gitbutler:") {
    return Err(anyhow!("not a snapshot commit"));
}
let entry = OplogEntry::from_str(&message)?;
Defensive patterns

Strategy: validation

Validate before calling

fn has_trailers(msg: &str) -> bool {
    msg.lines().rev().skip_while(|l| l.is_empty()).any(|l| l.contains(": ")) && msg.lines().count() >= 2
}
// call from_str only if has_trailers(message)

Prevention

When it happens

Trigger: Parsing a snapshot commit message that lacks a trailing trailer block — e.g. a hand-written or git-butchered commit message, or a snapshot created by a version that did not append trailers.

Common situations: Amended or rebased snapshot commits that lost trailers; manually editing oplog commits; restoring/parsing oplog entries from older repo states.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/ab0e0f6f69848bdf. Report an issue: GitHub.

Appendix: source

Thrown at crates/gitbutler-oplog/src/entry.rs:78

        self
    }

    pub fn with_trailers(mut self, trailers: impl IntoIterator<Item = Trailer>) -> Self {
        self.trailers.extend(trailers);
        self
    }
}

impl FromStr for SnapshotDetails {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let message_lines: Vec<&str> = s.lines().collect();
        let mut split: Vec<&[&str]> = message_lines.split(|line| line.is_empty()).collect();
        let title = split.remove(0).join("\n");
        let mut trailers: Vec<Trailer> = split
            .pop()
            .ok_or(anyhow!("No trailers found on snapshot commit message"))?
            .iter()
            .filter_map(|s| Trailer::from_str(s).ok())
            .collect();
        let body = split.iter().map(|v| v.join("\n")).join("\n\n");
        let body = if body.is_empty() { None } else { Some(body) };

        let version = trailers
            .iter()
            .find_map(|t| match t {
                Trailer::Version(version) => Some(*version),
                _ => None,
            })
            .context("No version found on snapshot commit message")?;

        let operation = trailers
            .iter()
            .find_map(|t| match t {
                Trailer::Operation(operation_kind) => Some(*operation_kind),

View on GitHub (pinned to 58e5313667)