gitbutlerapp/gitbutler · info
infinite loop should find a unique name
Error message
infinite loop should find a unique name
What it means
`find_unique_refname` (but-core/src/branch/generate.rs:31) walks `for num in start_num..` trying `base-{num}` against remote-tracking short names and existing references, returning on the first free candidate. Because `start_num..` is an infinite `usize` range whose only exits are the two `return`s, the trailing `unreachable!` is a compiler-satisfying marker, not a reachable error path; it could only execute after exhausting every `usize` value (or via arithmetic overflow, which panics on its own first).
Source
Thrown at crates/but-core/src/branch/generate.rs:84
.category()
.with_context(|| format!("Input branch {template} could not be categorized"))?;
let mut candidate_short = BString::default();
for num in start_num.. {
candidate_short.clear();
candidate_short.push_str(base);
candidate_short.push(b'-');
candidate_short.push_str(num.to_string());
if rtb_lut.contains(candidate_short.as_bstr()) {
continue;
}
let candidate_full = category.to_full_name(candidate_short.as_bstr())?;
if repo.try_find_reference(&candidate_full)?.is_none() {
return Ok(candidate_full);
}
}
unreachable!("infinite loop should find a unique name")
}
/// Find a new unique branch name, one that doesn't exist in `repo` yet.
///
/// See caveats of [`find_unique_refname()`].
pub fn unique_canned_refname(repo: &gix::Repository) -> anyhow::Result<gix::refs::FullName> {
let name = canned_refname(repo)?;
find_unique_refname(repo, name.as_ref())
}
fn generate_short_name_from_signature(author: &gix::actor::Signature) -> anyhow::Result<BString> {
let name = author.name.to_str_lossy();
// Split by whitespace to get words
let words: Vec<&str> = name.split_whitespace().collect();
// Try to extract initials from words
let prefix: Vec<&str> = words
.iter()View on GitHub (pinned to caf1f223d3)
Solutions
- Treat any sighting as a signal of memory corruption or a forged repository state, and capture a core dump / report upstream.
- If you must bound it defensively, convert the loop to a `while num != usize::MAX` with an explicit error return after the bound.
- Do not 'fix' it by removing the return paths; they are the normal exits.
Defensive patterns
Strategy: validation
Prevention
- Recognize this as a dead-code marker: the for-loop over an infinite range only exits via return.
- Any real occurrence implies memory corruption or a hostile repo — capture a core dump and report it rather than 'fixing' the line.
- Keep the two early returns (template free, candidate free) intact when refactoring the naming loop.
When it happens
Trigger: Practically untriggerable: it would require a repository containing every suffix from `start_num` up to `usize::MAX`. Debug-build overflow of `num` panics earlier with an arithmetic message instead.
Common situations: None in practice; the string mostly shows up in code review, static analysis, or crash-aggregation greps rather than real traces.
Related errors
- candidate turns always have review or branch evidence
- we never return these as the status iteration is configured
- BUG: we use 'matching' so there are no directories
- disabled
- BUG: this must have been deactivated
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/1c689d21951a5198.
Report an issue: GitHub.