{"record":{"id":"900cc1e2f19a1a0a","repo":"libnyanpasu/clash-nyanpasu","slug":"existing-non-symlink-file-at-refusing-to-repla","errorCode":null,"errorMessage":"existing non-symlink file at {}, refusing to replace","messagePattern":"existing non-symlink file at (.+?), refusing to replace","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/tauri/src/service/profile_file.rs","lineNumber":1580,"sourceCode":"            Err(e) => Err(e).with_context(|| format!(\"inspect profile file {}\", full.display())),\n        }\n    }\n\n    fn ensure_symlink(\n        &self,\n        path: &ManagedProfilePath,\n        target: &ExternalProfilePath,\n    ) -> anyhow::Result<()> {\n        let full = self.resolve(path)?;\n        self.ensure_managed_parent(&full)?;\n        match std::fs::symlink_metadata(&full) {\n            Ok(meta) if meta.file_type().is_symlink() => {\n                if symlink_points_to(&full, target.as_path())? {\n                    return Ok(());\n                }\n                std::fs::remove_file(&full)?;\n            }\n            Ok(_) => bail!(\n                \"existing non-symlink file at {}, refusing to replace\",\n                full.display()\n            ),\n            Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}\n            Err(e) => Err(e).with_context(|| format!(\"inspect profile file {}\", full.display()))?,\n        }\n        #[cfg(windows)]\n        std::os::windows::fs::symlink_file(target.as_path(), &full)?;\n        #[cfg(unix)]\n        std::os::unix::fs::symlink(target.as_path(), &full)?;\n        Ok(())\n    }\n}\n\nimpl ProfileMaterializationPort for ProfileFileService {\n    fn prepare_state_first(\n        &self,\n        path: &ManagedProfilePath,","sourceCodeStart":1562,"sourceCodeEnd":1598,"githubUrl":"https://github.com/libnyanpasu/clash-nyanpasu/blob/f7dbce2997c633e484f54788035e770b3ee99773/backend/tauri/src/service/profile_file.rs#L1562-L1598","documentation":"ProfileFileService::ensure_symlink refuses to replace an existing regular file (or directory) at a managed path with a symlink. This is a deliberate safety fence against destroying user data: the service will only swap out an existing symlink, never delete a real file that it did not create. The caller must explicitly remove the non-symlink entry before requesting a symlink there.","triggerScenarios":"Calling ProfileFileService::ensure_symlink(path, target) when `path` already exists as a regular file (symlink_metadata succeeds and the entry is not a symlink). Occurs when a profile item migrates from an inline/file-backed layout to an external-link layout while a real file still occupies the managed path, or a stale non-symlink file was left behind by a previous version or manual copy.","commonSituations":"Upgrading from an older app version that stored the profile as a regular file while the new version links to an external target; the user (or a sync tool like Dropbox/OneDrive) dropped a real file where the app expects to place its symlink; a restore/backup tool replaced symlinks with real file copies.","solutions":["Remove the existing regular file at the reported path (after backing up its contents) and retry ensure_symlink.","If the file's contents should be preserved, move them to the intended external target path first, then remove the file and call ensure_symlink.","Check for sync/backup software that materializes symlinks into real files and exclude the app data directory.","Use the service's remove(path) API instead of writing through the path, so the managed entry is deleted before linking."],"exampleFix":"// before\n// profile file was materialized as a regular file; this now fails\nservice.ensure_symlink(&path, &external)?;\n\n// after\nlet full = service.resolve(&path)?;\nif std::fs::symlink_metadata(&full).map(|m| !m.file_type().is_symlink()).unwrap_or(false) {\n    std::fs::rename(&full, backup_path)?; // preserve contents\n}\nservice.ensure_symlink(&path, &external)?;","handlingStrategy":"validation","validationCode":"let full = service.resolve(&path)?;\nmatch std::fs::symlink_metadata(&full) {\n    Ok(m) if m.file_type().is_symlink() => Ok(()),\n    Ok(_) => Err(anyhow!(\"{} is a regular file; move it to the external target first\", full.display())),\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),\n    Err(e) => Err(e.into()),\n}","typeGuard":"fn is_symlink(p: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.file_type().is_symlink()).unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Back up and remove any regular file at a managed path before switching that path to a symlink layout.","Exclude app data directories from file-sync tools that materialize symlinks.","After restoring from backups, verify managed paths are symlinks, not copied regular files.","Always use the service's remove/ensure_symlink APIs rather than raw filesystem writes in the managed tree."],"tags":["filesystem","symlink","safety-guard","profile"],"backgroundTag":"file-already-exists","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"}