libnyanpasu/clash-nyanpasu · error
failed to kill clash-verge-service.exe
Error message
failed to kill clash-verge-service.exe
What it means
During config migration a PermissionDenied copy triggered an elevated taskkill of clash-verge-service.exe; the command ran but returned a non-zero status, so the migration bails — the service could not be force-killed.
Solutions
- Stop clash-verge-service properly (its uninstaller or 'sc stop' with admin rights) and rerun the migration.
- Check whether the UAC prompt was declined; retry and accept elevation.
- Verify the service process name matches 'clash-verge-service.exe'; adjust the taskkill target if renamed.
- As a last resort, reboot (releases file locks) and rerun migration before starting the app.
Example fix
// before
let status = RunasCommand::new("cmd")
.args(&["/C", "taskkill", "/IM", "clash-verge-service.exe", "/F"])
.status()?;
if !status.success() {
anyhow::bail!("failed to kill clash-verge-service.exe")
}
// after
let status = RunasCommand::new("cmd")
.args(&["/C", "taskkill", "/IM", "clash-verge-service.exe", "/F"])
.status()?;
if !status.success() {
anyhow::bail!("failed to kill clash-verge-service.exe; stop the service manually (sc stop clash_verge_service) and retry");
} Defensive patterns
Strategy: try-catch
Validate before calling
// detect the locking service before attempting migration
let locked = std::process::Command::new("tasklist")
.args(&["/FI", "IMAGENAME eq clash-verge-service.exe"])
.output()
.map(|o| o.status.success() && String::from_utf8_lossy(&o.stdout).contains("clash-verge-service"))
.unwrap_or(false);
if locked { println!("stop clash-verge-service before migrating"); } Try / catch
match do_config_migration().await {
Err(e) if e.to_string().contains("failed to kill clash-verge-service") => {
eprintln!("stop the service manually (admin): taskkill /IM clash-verge-service.exe /F, then retry");
}
other => other,
} Prevention
- Shut down clash-verge-service via the app before upgrading
- Accept the UAC elevation prompt when shown
- Reboot if file locks persist, then rerun migration
When it happens
Trigger: do_config_migration encountering fs_extra PermissionDenied while moving the old app dir, then RunasCommand taskkill /IM clash-verge-service.exe /F failing — service protected, UAC declined, or executable name changed.
Common situations: Upgrading versions while clash-verge-service is running and locking files; user cancels the UAC elevation prompt; service installed under a different name/path.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Can't create listener
- cannot repair typed clash config before split_legacy_config…
- child process failed
- clean-schema output failed validation
- clean-schema output rejected by domain model
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/4c1669236824e652.
Report an issue: GitHub.
Appendix: source
Thrown at backend/tauri/src/utils/init/mod.rs:254
}
}
Ok(None)
}
pub fn do_config_migration(old_app_dir: &PathBuf, app_dir: &PathBuf) -> anyhow::Result<()> {
let copy_option = CopyOptions::new();
let copy_option = copy_option.overwrite(true);
let copy_option = copy_option.content_only(true);
if let Err(e) = fs_extra::dir::move_dir(old_app_dir, app_dir, ©_option) {
match e.kind {
#[cfg(windows)]
fs_extra::error::ErrorKind::PermissionDenied => {
// It seems that clash-verge-service is running, so kill it.
let status = RunasCommand::new("cmd")
.args(&["/C", "taskkill", "/IM", "clash-verge-service.exe", "/F"])
.status()?;
if !status.success() {
anyhow::bail!("failed to kill clash-verge-service.exe")
}
fs::rename(old_app_dir, app_dir)?;
}
_ => return Err(e.into()),
};
}
Ok(())
}
View on GitHub (pinned to f7dbce2997)