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

  1. Clean up completed/stale operations in the materialization root (run reconcile or manually remove old operation dirs with valid ids), then retry.
  2. Verify the root passed to allocate_operation_id is the correct staging directory; a wrong root can make the in-use check misbehave.
  3. If the in-use check is faulty (always true), fix the lookup; the collision probability is otherwise negligible.
  4. 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

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)