libnyanpasu/clash-nyanpasu · error
failed to allocate a unique profile materialization…
Error message
failed to allocate a unique profile materialization operation id
What it means
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.
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.
Example fix
// before
// hundreds of stale operation dirs in staging root cause repeated collisions
// after
for stale in stale_operation_ids(root) {
client.compensate(root, &stale).await?; // clean before allocating
}
let op_id = client.allocate_operation_id(root).await?; Defensive patterns
Strategy: retry
Validate before calling
// prune stale operations before allocating
for entry in std::fs::read_dir(root)? {
let entry = entry?;
if operation_is_expired(&entry.path()) {
std::fs::remove_dir_all(entry.path())?;
}
} Try / catch
let op_id = loop {
match client.allocate_operation_id(root).await {
Ok(id) => break id,
Err(e) if e.to_string().contains("unique profile materialization") => {
cleanup_stale_operations(root).await?; // then retry
}
Err(e) => return Err(e),
}
}; Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/6b652f5ff571fb9d.
Report an issue: GitHub.
Appendix: source
Thrown at backend/tauri/src/service/profile_file.rs:1074
if artifact_paths
.iter()
.any(|path| std::fs::symlink_metadata(path).is_ok())
{
return true;
}
JournalLocation::ALL.iter().any(|location| {
std::fs::symlink_metadata(Self::journal_path(root, *location, operation_id)).is_ok()
})
}
fn allocate_operation_id(root: &Path) -> anyhow::Result<String> {
for _ in 0..16 {
let operation_id = nanoid::nanoid!(16, &nanoid::alphabet::SAFE);
if !Self::operation_id_in_use(root, &operation_id) {
return Ok(operation_id);
}
}
bail!("failed to allocate a unique profile materialization operation id")
}
fn prepare_materialization(
&self,
path: &ManagedProfilePath,
resource: &MaterializationResource,
expected_revision: u64,
location: JournalLocation,
) -> anyhow::Result<PreparedMaterialization> {
let root = self.ensure_materialization_layout()?;
let target = self.resolve(path)?;
self.ensure_managed_parent(&target)?;
Self::ensure_replaceable_target(&target)?;
let operation_id = Self::allocate_operation_id(&root)?;
if let Err(error) = (|| {
Self::stage_resource(&root, &operation_id, resource)?;
Self::capture_backup(&root, &operation_id, &target)?;View on GitHub (pinned to f7dbce2997)