gitbutlerapp/gitbutler · error

too many IDs

Error message

too many IDs

What it means

GitButler assigns short `UintId` identifiers (committed-file markers etc.) from a monotonically increasing counter capped at `UintId::LIMIT`. `next_available` first advances the counter past any marked-in-use IDs and then bails if the counter reached the limit, meaning the operation can no longer allocate a unique ID.

Solutions

  1. Reduce the number of entries in the workspace (commit/clean up applied files) and retry.
  2. Reset the workspace state so the ID counter restarts (e.g. by re-initializing the session).
  3. If hit with a normal number of files, file a bug — IDs are likely being leaked rather than reused.
Defensive patterns

Strategy: try-catch

Validate before calling

// guard before allocating more IDs
if usage.next_available().is_err() { /* reduce workspace entries or reset */ }

Try / catch

match id_usage.next_available() {
    Err(e) if e.to_string() == "too many IDs" => cleanup_workspace_and_retry(),
    other => other?,
}

Prevention

When it happens

Trigger: Repeatedly calling next_available (e.g. assigning IDs to many workspace files/committed entries) until next_uint_id reaches UintId::LIMIT within a single workspace/session state.

Common situations: Workspaces with an extreme number of tracked/committed entries in one session; long-lived state where IDs are never released; a bug leaking ID allocations.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18). Data as JSON: /api/errors/b9462ce74819342c. Report an issue: GitHub.

Appendix: source

Thrown at crates/but/src/id/id_usage.rs:104

#[derive(Clone, Default, Debug)]
pub(crate) struct IdUsage {
    /// A [UintId] is used if it's in this set.
    uint_ids_used: HashSet<UintId>,
    /// A [UintId] is used if it's less than this number.
    next_uint_id: UintId,
}

impl IdUsage {
    pub(crate) fn mark_used(&mut self, uint_id: UintId) {
        if self.next_uint_id.0 <= uint_id.0 {
            self.uint_ids_used.insert(uint_id);
        }
    }

    pub(crate) fn next_available(&mut self) -> anyhow::Result<UintId> {
        self.forward_next_uint_id_to_not_conflict_with_marked();
        if self.next_uint_id.0 >= UintId::LIMIT {
            bail!("too many IDs");
        }
        let result = self.next_uint_id;
        self.next_uint_id = UintId(self.next_uint_id.0 + 1);
        Ok(result)
    }

    pub(crate) fn skip_available(&mut self) {
        self.forward_next_uint_id_to_not_conflict_with_marked();
        if self.next_uint_id.0 < UintId::LIMIT {
            self.next_uint_id = UintId(self.next_uint_id.0 + 1);
        }
    }

    pub(crate) fn forward_next_uint_id_to_not_conflict_with_marked(&mut self) {
        while self.uint_ids_used.remove(&self.next_uint_id) {
            self.next_uint_id = UintId(self.next_uint_id.0 + 1);
        }
    }

View on GitHub (pinned to 58e5313667)