libnyanpasu/clash-nyanpasu · error

staged resource is missing and target hash does not match

Error message

staged resource is missing and target hash does not match

What it means

promote_resource could not read the staged resource for the operation, and the target file at its final location does not hash to the expected value. Together this means neither the staging area nor the target holds the verified content, so the transaction cannot be considered complete and it fails instead of silently promoting unverified data.

Source

Thrown at backend/tauri/src/service/profile_file.rs:910

            Err(error) => return Err(error).context("inspect ready symlink"),
        }
        Ok(ready)
    }

    fn promote_resource(
        &self,
        root: &Path,
        operation_id: &str,
        target: &Path,
        expected_hash: &str,
    ) -> anyhow::Result<()> {
        self.ensure_managed_parent(target)?;
        Self::ensure_replaceable_target(target)?;
        let Some(resource) = Self::read_staged_resource(root, operation_id, expected_hash)? else {
            if Self::path_hash(target)? == expected_hash {
                return Ok(());
            }
            bail!("staged resource is missing and target hash does not match");
        };

        // Static symlink/reparse validation is mandatory. A same-user parent
        // swap after this recheck is outside this desktop app's local trust
        // boundary; descriptor-based confinement is intentionally not added.
        match resource {
            StoredResource::File { path } => {
                self.ensure_managed_parent(target)?;
                Self::ensure_replaceable_target(target)?;
                replace_atomic(&path, target).with_context(|| {
                    format!(
                        "promote staged file {} -> {}",
                        path.display(),
                        target.display()
                    )
                })?;
            }
            StoredResource::Symlink {

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Re-download/re-materialize the profile resource: create a new operation via prepare_materialization so the staged file is recreated, then promote.
  2. Restore the staged resource file for this operation_id (correct hash) and rerun promote.
  3. If the target is actually correct, recompute its hash and confirm expected_hash in the journal matches; a stale journal hash is the real bug.
  4. Run compensate to roll the operation back cleanly before retrying.

Example fix

// before
// staged file deleted by cleanup, target no longer matches journal hash
// after
let op_id = client.prepare_materialization(&managed_path, resource).await?;
client.promote(root, &op_id).await?;
Defensive patterns

Strategy: retry

Validate before calling

// caller-side sanity check before promote
let staged_exists = staged_resource_path(root, op_id).exists();
let target_hash = hash_file(&target_path)?;
if !staged_exists && target_hash != expected_hash {
    // re-materialize instead of promoting
    let new_id = client.prepare_materialization(&managed_path, resource).await?;
}

Type guard

fn staged_resource_available(root: &Path, op_id: &str, expected: &str) -> bool {
    read_staged_resource_hash(root, op_id).map(|h| h == expected).unwrap_or(false)
}

Try / catch

match client.promote(root, op_id).await {
    Err(e) if e.to_string().contains("staged resource is missing") => {
        let fresh = client.prepare_materialization(&managed_path, resource).await?;
        client.promote(root, &fresh).await
    }
    r => r,
}

Prevention

When it happens

Trigger: promote() called when the staged resource file is missing (deleted, never written, or lost across journal locations) AND the target's content hash differs from expected_hash — e.g. an interrupted prepare_materialization plus a partially modified target.

Common situations: Disk cleanup removed staging files between runs; a crash occurred after journal creation but before staging completed; the target was edited or corrupted by another process; migrating staging dirs between machines.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/551849ff1a4a0973. Report an issue: GitHub.