{"record":{"id":"b9462ce74819342c","repo":"gitbutlerapp/gitbutler","slug":"too-many-ids","errorCode":null,"errorMessage":"too many IDs","messagePattern":"too many IDs","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/id/id_usage.rs","lineNumber":104,"sourceCode":"#[derive(Clone, Default, Debug)]\npub(crate) struct IdUsage {\n    /// A [UintId] is used if it's in this set.\n    uint_ids_used: HashSet<UintId>,\n    /// A [UintId] is used if it's less than this number.\n    next_uint_id: UintId,\n}\n\nimpl IdUsage {\n    pub(crate) fn mark_used(&mut self, uint_id: UintId) {\n        if self.next_uint_id.0 <= uint_id.0 {\n            self.uint_ids_used.insert(uint_id);\n        }\n    }\n\n    pub(crate) fn next_available(&mut self) -> anyhow::Result<UintId> {\n        self.forward_next_uint_id_to_not_conflict_with_marked();\n        if self.next_uint_id.0 >= UintId::LIMIT {\n            bail!(\"too many IDs\");\n        }\n        let result = self.next_uint_id;\n        self.next_uint_id = UintId(self.next_uint_id.0 + 1);\n        Ok(result)\n    }\n\n    pub(crate) fn skip_available(&mut self) {\n        self.forward_next_uint_id_to_not_conflict_with_marked();\n        if self.next_uint_id.0 < UintId::LIMIT {\n            self.next_uint_id = UintId(self.next_uint_id.0 + 1);\n        }\n    }\n\n    pub(crate) fn forward_next_uint_id_to_not_conflict_with_marked(&mut self) {\n        while self.uint_ids_used.remove(&self.next_uint_id) {\n            self.next_uint_id = UintId(self.next_uint_id.0 + 1);\n        }\n    }","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but/src/id/id_usage.rs#L86-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Reduce the number of entries in the workspace (commit/clean up applied files) and retry.","Reset the workspace state so the ID counter restarts (e.g. by re-initializing the session).","If hit with a normal number of files, file a bug — IDs are likely being leaked rather than reused."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// guard before allocating more IDs\nif usage.next_available().is_err() { /* reduce workspace entries or reset */ }\n","typeGuard":null,"tryCatchPattern":"match id_usage.next_available() {\n    Err(e) if e.to_string() == \"too many IDs\" => cleanup_workspace_and_retry(),\n    other => other?,\n}","preventionTips":["Commit or remove workspace entries regularly so IDs don't accumulate unbounded.","Monitor workspace size; keep applied-file counts well below the ID limit.","Report leaks if the error occurs with few files."],"tags":["ids","limit-exceeded","workspace"],"backgroundTag":"value-out-of-range","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}