gitbutlerapp/gitbutler · error
Invalid trailer format, expected `key: value`
Error message
Invalid trailer format, expected `key: value`
What it means
CommitTrailer::from_str parses one serialized trailer line and requires a colon separating key from value (it splits on the first ':'). Input without any colon — a bare word or a key that lost its ': value' suffix — fails with this message. 'key:' with an empty value is accepted, and newlines inside values must be escaped as literal \n, so only colon-less strings are rejected.
Source
Thrown at crates/but-core/src/snapshot/mod.rs:57
pub key: String,
/// Trailer value.
pub value: String,
}
impl Display for CommitTrailer {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
let escaped_value = self.value.replace('\n', "\\n");
write!(f, "{}: {}", self.key, escaped_value)
}
}
impl FromStr for CommitTrailer {
type Err = anyhow::Error;
fn from_str(s: &str) -> anyhow::Result<Self, Self::Err> {
let mut parts = s.splitn(2, ':');
let (Some(key), Some(value)) = (parts.next(), parts.next()) else {
return Err(anyhow!("Invalid trailer format, expected `key: value`"));
};
let unescaped_value = value.trim().replace("\\n", "\n");
Ok(Self {
key: key.trim().to_string(),
value: unescaped_value,
})
}
}
/// Metadata attached to [`Commit`]s holding snapshots.
pub struct CommitMetadata {
/// The name of the operation that created the commit.
/// This is an internal string.
pub operation: String,
/// The title of the commit for user consumption, typically created using information from `trailers`.
pub title: String,
/// Properties to be stored with the commit.
pub trailers: Vec<CommitTrailer>,View on GitHub (pinned to 2497b8007a)
Solutions
- Validate each line contains ':' (split_once) before parsing; reject or skip bad lines with a clear index.
- Fix the producer to always emit 'key: value' with \n-escaped newlines in values.
- When accepting user input, pre-check with a pattern like ^[^:]+: .
Example fix
// before
let trailer: CommitTrailer = line.parse()?;
// after
anyhow::ensure!(
line.split_once(':').is_some(),
"malformed trailer line (expected `key: value`): {line:?}"
);
let trailer: CommitTrailer = line.parse()?; Defensive patterns
Strategy: validation
Validate before calling
for (i, line) in lines.iter().enumerate() {
if line.split_once(':').is_none() {
anyhow::bail!("trailer[{i}] is not `key: value`: {line:?}");
}
} Type guard
fn is_trailer_line(s: &str) -> bool {
s.split_once(':').is_some()
} Prevention
- Write trailers with a single serializer that always formats 'key: value'.
- Escape newlines as \n when serializing values; unescape only after a successful parse.
- Reject free-text lines before they reach the trailer parser.
When it happens
Trigger: Deserializing CommitMetadata trailers where one line is malformed: 'Co-authored-by' without '<email>', a line of free text slipping into the trailers list, or concatenation bugs that dropped the colon.
Common situations: Hand-edited snapshot/metadata files; trailers split on the wrong delimiter; migration code writing raw multi-line text instead of escaped 'key: value' pairs.
Related errors
- Stack has no ID
- This metadata backend doesn't support branch stack order
- DefaultTargetNotFound
- MCP Apps capability is an object
- symbols must always be initialized
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/c139e2951c4b9de6.
Report an issue: GitHub.