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

  1. Validate each line contains ':' (split_once) before parsing; reject or skip bad lines with a clear index.
  2. Fix the producer to always emit 'key: value' with \n-escaped newlines in values.
  3. 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

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


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/c139e2951c4b9de6. Report an issue: GitHub.