{"record":{"id":"8fbfa581d35f350b","repo":"libnyanpasu/clash-nyanpasu","slug":"runtime-revision-space-exhausted","errorCode":null,"errorMessage":"runtime revision space exhausted","messagePattern":"runtime revision space exhausted","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/client/runtime.rs","lineNumber":44,"sourceCode":"\nimpl RuntimeRevision {\n    pub fn get(self) -> u64 {\n        self.0\n    }\n}\n\npub(crate) struct RuntimeRevisionAllocator(u64);\n\nimpl RuntimeRevisionAllocator {\n    pub(crate) fn new() -> Self {\n        Self(0)\n    }\n\n    pub(crate) fn allocate(&mut self) -> anyhow::Result<RuntimeRevision> {\n        self.0 = self\n            .0\n            .checked_add(1)\n            .ok_or_else(|| anyhow::anyhow!(\"runtime revision space exhausted\"))?;\n        Ok(RuntimeRevision(self.0))\n    }\n}\n\n#[derive(Debug, Clone)]\npub(crate) struct RuntimeSnapshotData {\n    pub config: Mapping,\n    pub exists_keys: Vec<String>,\n    pub postprocessing_output: PostProcessingOutput,\n    pub(crate) inspection: Arc<super::runtime_inspection::RuntimeInspectionData>,\n}\n\n#[derive(Debug, Clone)]\npub struct RuntimeSnapshot {\n    pub(crate) inspection_id: String,\n    pub revision: RuntimeRevision,\n    pub target_core: ClashCore,\n    pub product_sha256: [u8; 32],","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/client/runtime.rs#L26-L62","documentation":"`RuntimeRevisionAllocator::allocate` increments an internal counter and returns `RuntimeRevision`; when the counter is at `u64::MAX` (checked_add overflows), allocation fails with this error. It protects the monotonic revision contract used for snapshot ordering.","triggerScenarios":"Calling `allocate` after the process has allocated `u64::MAX` revisions — practically only possible via an allocation loop that runs ~1.8e19 times, or a test that wraps the counter (e.g. `runtime_revision_allocator_is_monotonic`).","commonSituations":"Only in theory: an unbounded runtime-config update loop running for years, or a test that pre-seeds the allocator near the maximum to exercise overflow handling.","solutions":["Fix the runaway loop that allocates revisions without bound (profile the repeated update path)","Replace the allocator instance (reset the counter) if the process is truly long-lived and revisions are no longer compared across restarts","Widen the revision type or switch to a UUID/epoch-based scheme if u64 exhaustion is a real requirement"],"exampleFix":"// before\nfor _ in 0..u64::MAX { allocator.allocate()?; } // exhausts revision space\n// after\nlet rev = allocator.allocate()?; // allocate once per actual runtime-config commit","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match allocator.allocate() {\n    Ok(rev) => rev,\n    Err(e) if e.to_string().contains(\"revision space exhausted\") => {\n        // recreate the allocator or abort the loop; log the runaway-update condition\n        eprintln!(\"revision allocator exhausted: {e}\");\n        return;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Only allocate a revision per actual runtime-config commit, never in a loop per attempt","Reuse a single allocator per process lifetime and avoid reseeding it near u64::MAX","Monitor runtime-config update frequency to catch runaway loops early"],"tags":["overflow","revision","internal"],"backgroundTag":"value-out-of-range","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}