{"record":{"id":"6b652f5ff571fb9d","repo":"libnyanpasu/clash-nyanpasu","slug":"failed-to-allocate-a-unique-profile-materializatio","errorCode":null,"errorMessage":"failed to allocate a unique profile materialization operation id","messagePattern":"failed to allocate a unique profile materialization operation id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1074,"sourceCode":"        if artifact_paths\n            .iter()\n            .any(|path| std::fs::symlink_metadata(path).is_ok())\n        {\n            return true;\n        }\n        JournalLocation::ALL.iter().any(|location| {\n            std::fs::symlink_metadata(Self::journal_path(root, *location, operation_id)).is_ok()\n        })\n    }\n\n    fn allocate_operation_id(root: &Path) -> anyhow::Result<String> {\n        for _ in 0..16 {\n            let operation_id = nanoid::nanoid!(16, &nanoid::alphabet::SAFE);\n            if !Self::operation_id_in_use(root, &operation_id) {\n                return Ok(operation_id);\n            }\n        }\n        bail!(\"failed to allocate a unique profile materialization operation id\")\n    }\n\n    fn prepare_materialization(\n        &self,\n        path: &ManagedProfilePath,\n        resource: &MaterializationResource,\n        expected_revision: u64,\n        location: JournalLocation,\n    ) -> anyhow::Result<PreparedMaterialization> {\n        let root = self.ensure_materialization_layout()?;\n        let target = self.resolve(path)?;\n        self.ensure_managed_parent(&target)?;\n        Self::ensure_replaceable_target(&target)?;\n        let operation_id = Self::allocate_operation_id(&root)?;\n\n        if let Err(error) = (|| {\n            Self::stage_resource(&root, &operation_id, resource)?;\n            Self::capture_backup(&root, &operation_id, &target)?;","sourceCodeStart":1056,"sourceCodeEnd":1092,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1056-L1092","documentation":"allocate_operation_id tried 16 times to generate a nanoid collision-free operation id, checking operation_id_in_use each time, and every candidate already exists in the staging root. This is effectively an internal invariant failure — the id space is astronomically large, so 16 collisions indicate stale accumulation or a broken in-use check.","triggerScenarios":"16 consecutive nanoid candidates collide with existing operation directories/journals in the materialization root; practically only when thousands of stale operations accumulate, or when operation_id_in_use wrongly reports collisions (e.g. wrong root path scanned, glob matching everything).","commonSituations":"Staging root never cleaned of old operations over long uptimes; a misconfigured root pointing at a directory where the existence check always returns true; a bug making all ids appear in use.","solutions":["Clean up completed/stale operations in the materialization root (run reconcile or manually remove old operation dirs with valid ids), then retry.","Verify the root passed to allocate_operation_id is the correct staging directory; a wrong root can make the in-use check misbehave.","If the in-use check is faulty (always true), fix the lookup; the collision probability is otherwise negligible.","Retry the operation after cleanup — this is not a permanent condition."],"exampleFix":"// before\n// hundreds of stale operation dirs in staging root cause repeated collisions\n// after\nfor stale in stale_operation_ids(root) {\n    client.compensate(root, &stale).await?; // clean before allocating\n}\nlet op_id = client.allocate_operation_id(root).await?;","handlingStrategy":"retry","validationCode":"// prune stale operations before allocating\nfor entry in std::fs::read_dir(root)? {\n    let entry = entry?;\n    if operation_is_expired(&entry.path()) {\n        std::fs::remove_dir_all(entry.path())?;\n    }\n}","typeGuard":null,"tryCatchPattern":"let op_id = loop {\n    match client.allocate_operation_id(root).await {\n        Ok(id) => break id,\n        Err(e) if e.to_string().contains(\"unique profile materialization\") => {\n            cleanup_stale_operations(root).await?; // then retry\n        }\n        Err(e) => return Err(e),\n    }\n};","preventionTips":["Run reconcile at startup to clean abandoned operations.","Cap the number of live operations and expire old ones.","Verify the staging root passed in is the correct, app-owned directory.","Treat repeated allocation failure as a bug: it implies a broken in-use check."],"tags":["internal","id-generation","staging"],"backgroundTag":"internal-invariant-violation","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"}