gitbutlerapp/gitbutler · error
Failed to parse branch_ref_bytes
Error message
Failed to parse branch_ref_bytes: {e} What it means
When converting a stored database HunkAssignment row into the domain HunkAssignment, the persisted branch_ref_bytes must be a valid gix::refs::FullName (e.g. refs/heads/...). If parsing fails, the row contains a malformed ref name and the conversion aborts with this error.
Solutions
- Fix or clear the malformed branch_ref_bytes value in the HunkAssignment table row
- Re-run assignment so rows are rewritten with valid refs
- Check for version mismatch between the tool that wrote the DB and the reader; upgrade/downgrade accordingly
Example fix
// before // row.branch_ref_bytes = "heads/my-branch" (invalid, missing refs/) // after // row.branch_ref_bytes = "refs/heads/my-branch"
Defensive patterns
Strategy: try-catch
Validate before calling
if let Some(b) = &row.branch_ref_bytes {
if gix::refs::FullName::try_from(BString::from(b.clone())).is_err() {
eprintln!("Skipping row with malformed branch_ref_bytes: {b:?}");
}
} Type guard
fn valid_ref(b: &BString) -> Option<gix::refs::FullName> {
gix::refs::FullName::try_from(b.clone()).ok()
} Try / catch
match HunkAssignment::try_from(row) {
Ok(a) => use(a),
Err(e) if e.to_string().contains("branch_ref_bytes") => {
log::warn!("corrupt row skipped: {e}");
// re-assign or repair the row
}
Err(e) => return Err(e),
} Prevention
- Always write refs in full refs/heads/... form
- Validate ref bytes before persisting to the DB
- Handle schema/version drift between writer and reader versions
When it happens
Trigger: TryFrom<but_db::HunkAssignment> for HunkAssignment encountering branch_ref_bytes that does not parse as a gix::refs::FullName — corrupt or hand-edited DB rows, or rows written by an older version with a different ref format.
Common situations: Schema/version drift after upgrading GitButler; manual DB edits; bugs in earlier writers persisting invalid ref strings.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- commit prefix ' ' is ambiguous
- commit ' ' is not part of the editable divergence
- line : invalid merge commit
- line : invalid pick commit
- line : invalid squash commit
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/956c0590cfc2a356.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but-hunk-assignment/src/lib.rs:128
.hunk_header
.as_ref()
.and_then(|h| serde_json::from_str(h).ok());
let legacy_stack_id = value
.stack_id
.as_ref()
.and_then(|id| uuid::Uuid::parse_str(id).ok())
.map(StackId::from);
Ok(HunkAssignment {
id: value.id.map(|id| Uuid::parse_str(&id)).transpose()?,
hunk_header: header,
path: value.path,
path_bytes: value.path_bytes.into(),
stack_id: legacy_stack_id,
branch_ref_bytes: value
.branch_ref_bytes
.map(|b| gix::refs::FullName::try_from(BString::from(b)))
.transpose()
.map_err(|e| anyhow::anyhow!("Failed to parse branch_ref_bytes: {e}"))?,
line_nums_added: None, // derived data (not persisted)
line_nums_removed: None, // derived data (not persisted)
diff: None, // derived data (not persisted)
})
}
}
impl TryFrom<HunkAssignment> for but_db::HunkAssignment {
type Error = anyhow::Error;
fn try_from(value: HunkAssignment) -> Result<Self, Self::Error> {
let header = value
.hunk_header
.map(|h| {
serde_json::to_string(&h)
.map_err(|e| anyhow::anyhow!("Failed to serialize hunk_header: {e}"))
})
.transpose()?;
Ok(but_db::HunkAssignment {View on GitHub (pinned to 58e5313667)