{"record":{"id":"d60d489323c0de45","repo":"libnyanpasu/clash-nyanpasu","slug":"staged-symlink-hash-mismatch","errorCode":null,"errorMessage":"staged symlink hash mismatch","messagePattern":"staged symlink hash mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":794,"sourceCode":"            bail!(\"materialization has multiple staged resources\");\n        }\n        if let Some(metadata) = file_metadata {\n            if is_symlink_or_reparse(&metadata) || !metadata.is_file() {\n                bail!(\"staged file is not a regular file\");\n            }\n            let content = std::fs::read(&file_path)?;\n            if hash_tagged(b\"file\", &content) != expected_hash {\n                bail!(\"staged file hash mismatch\");\n            }\n            return Ok(Some(StoredResource::File { path: file_path }));\n        }\n        if let Some(metadata) = link_metadata {\n            if is_symlink_or_reparse(&metadata) || !metadata.is_file() {\n                bail!(\"staged symlink specification is not a regular file\");\n            }\n            let target = std::fs::read_to_string(&link_path)?;\n            if hash_tagged(b\"symlink\", target.as_bytes()) != expected_hash {\n                bail!(\"staged symlink hash mismatch\");\n            }\n            return Ok(Some(StoredResource::Symlink {\n                target: ExternalProfilePath::new(target)?,\n            }));\n        }\n        Ok(None)\n    }\n\n    fn capture_backup(root: &Path, operation_id: &str, target: &Path) -> anyhow::Result<()> {\n        match std::fs::symlink_metadata(target) {\n            Ok(metadata) if metadata.file_type().is_symlink() => {\n                let link_target = std::fs::read_link(target)?;\n                let link_target = link_target\n                    .to_str()\n                    .context(\"managed symlink target is not valid UTF-8\")?;\n                Self::write_private_file_new(\n                    &Self::backup_link_path(root, operation_id),\n                    link_target.as_bytes(),","sourceCodeStart":776,"sourceCodeEnd":812,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L776-L812","documentation":"The staged symlink-spec file was read, but its target string does not match the expected tagged hash (hash_tagged(b\"symlink\", target_bytes)). The symlink target changed after staging or the expected hash belongs to a different resource. This integrity check prevents promoting a symlink pointing somewhere other than what was validated.","triggerScenarios":"std::fs::read_to_string(stage_link_path) succeeded but hash_tagged(b\"symlink\", target.as_bytes()) != expected_hash — the spec file content changed after staging (concurrent write, crash-partial write), or the caller passed an expected_hash computed for a file resource instead of the symlink resource.","commonSituations":"Reusing an operation_id with an expected hash from a previous file-based materialization; concurrent modification of the staging directory; a partially flushed write persisted only part of the target string.","solutions":["Re-run the materialization so the symlink spec is restaged and the hash recomputed.","Ensure the expected_hash was computed with hash_tagged(b\"symlink\", ...) over the same target string that was staged (not the b\"file\" variant).","Serialize access to the operation_id — make sure no other task stages/reads the same operation concurrently.","If a crash left a partial spec file, clear the staging dir for this operation_id before retrying."],"exampleFix":"// before: expected hash computed with wrong domain tag\nlet expected = hash_tagged(b\"file\", target.as_bytes());\n// after: match the staged resource kind\nlet expected = hash_tagged(b\"symlink\", target.as_bytes());","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"staged symlink hash mismatch\") => {\n        remove_stale_staging(root, op_id)?;\n        retry_materialization() // restage target string and recompute hash\n    }\n    other => other,\n}","preventionTips":["Compute the expected hash with the b\"symlink\" domain tag, matching the staged resource kind.","Never reuse operation IDs between file and symlink materializations.","Avoid concurrent staging/read of the same operation_id."],"tags":["hash","integrity","symlink","profile-materialization"],"backgroundTag":"checksum-mismatch","analyzedSha":"f7dbce2997c633e484f54788035e770b3ee99773","analyzedAt":"2026-09-08T01:24:59.197Z","contentChangedAt":"2026-09-08T01:24:59.197Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}