{"record":{"id":"ab0e0f6f69848bdf","repo":"gitbutlerapp/gitbutler","slug":"no-trailers-found-on-snapshot-commit-message","errorCode":null,"errorMessage":"No trailers found on snapshot commit message","messagePattern":"No trailers found on snapshot commit message","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gitbutler-oplog/src/entry.rs","lineNumber":78,"sourceCode":"        self\n    }\n\n    pub fn with_trailers(mut self, trailers: impl IntoIterator<Item = Trailer>) -> Self {\n        self.trailers.extend(trailers);\n        self\n    }\n}\n\nimpl FromStr for SnapshotDetails {\n    type Err = anyhow::Error;\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        let message_lines: Vec<&str> = s.lines().collect();\n        let mut split: Vec<&[&str]> = message_lines.split(|line| line.is_empty()).collect();\n        let title = split.remove(0).join(\"\\n\");\n        let mut trailers: Vec<Trailer> = split\n            .pop()\n            .ok_or(anyhow!(\"No trailers found on snapshot commit message\"))?\n            .iter()\n            .filter_map(|s| Trailer::from_str(s).ok())\n            .collect();\n        let body = split.iter().map(|v| v.join(\"\\n\")).join(\"\\n\\n\");\n        let body = if body.is_empty() { None } else { Some(body) };\n\n        let version = trailers\n            .iter()\n            .find_map(|t| match t {\n                Trailer::Version(version) => Some(*version),\n                _ => None,\n            })\n            .context(\"No version found on snapshot commit message\")?;\n\n        let operation = trailers\n            .iter()\n            .find_map(|t| match t {\n                Trailer::Operation(operation_kind) => Some(*operation_kind),","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/gitbutler-oplog/src/entry.rs#L60-L96","documentation":"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).","triggerScenarios":"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.","commonSituations":"Amended or rebased snapshot commits that lost trailers; manually editing oplog commits; restoring/parsing oplog entries from older repo states.","solutions":["Use only oplog snapshot commits that were created by the tool (trailers intact).","If trailers were lost, the commit cannot be interpreted as a snapshot — recreate the snapshot operation.","Guard parsing: check the message for a trailer section (e.g. contains a known trailer key) before calling from_str.","Check for older-format snapshots and migrate them instead of parsing directly."],"exampleFix":"// before\nlet entry = OplogEntry::from_str(&message)?; // panics/errors without trailers\n// after\nif !message.contains(\"gitbutler:\") {\n    return Err(anyhow!(\"not a snapshot commit\"));\n}\nlet entry = OplogEntry::from_str(&message)?;","handlingStrategy":"validation","validationCode":"fn has_trailers(msg: &str) -> bool {\n    msg.lines().rev().skip_while(|l| l.is_empty()).any(|l| l.contains(\": \")) && msg.lines().count() >= 2\n}\n// call from_str only if has_trailers(message)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never amend or rewrite oplog snapshot commits.","Validate commit messages contain the expected trailer keys before parsing.","Handle legacy snapshots from older versions via a migration path."],"tags":["oplog","parsing","commit-message","trailers"],"backgroundTag":"schema-validation-failed","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}