libnyanpasu/clash-nyanpasu · error
{stderr}
Error message
{stderr} What it means
`grant_permission` escalates privileges for the core binary (osascript on macOS, pkexec/sudo setcap on Linux) and, when the elevated command exits non-zero, fails with the raw stderr of that command. The message is entirely the child process' stderr, so the text varies (e.g. auth dialogs cancelled, sudo password failures, setcap errors).
Solutions
- Read the returned stderr to identify the actual OS-level failure (cancelled prompt vs. command error) and retry with the prompt accepted.
- Verify pkexec/polkit or sudo is available and configured on the system, or run the app with sufficient privileges already.
- Re-run after correcting the binary path (spaces/special characters) that broke the elevated shell command.
Defensive patterns
Strategy: try-catch
Validate before calling
let which = Command::new("which").arg("sudo").output()?;
if !which.status.success() { return Err(anyhow::anyhow!("no privilege-escalation helper available")); } Try / catch
match grant_permission(&core_path) {
Err(e) => {
let stderr = e.to_string();
if stderr.contains("User canceled") || stderr.contains("canceled") {
log::info!("user declined elevation");
} else {
return Err(anyhow::anyhow!("grant_permission failed: {stderr}"));
}
}
Ok(()) => {}
} Prevention
- Detect user-cancelled prompts (macOS 'User canceled', pkexec dismissal) and treat them as benign.
- Check for pkexec/sudo availability before invoking grant_permission.
- Avoid paths with spaces/special characters for the core binary, or test escaping on the target platform.
- If the app already runs as root/admin, skip the escalation step entirely.
When it happens
Trigger: Calling `grant_permission(path)` where the `osascript`/`sudo`/`pkexec` child exits non-zero: user cancels the UAC-like prompt, password entry fails, the path contains unescaped characters, or setcap is unavailable.
Common situations: Linux systems without policykit configured; user cancels the macOS administrator prompt; sudo requires a TTY; binary path has spaces on systems where escaping is insufficient; running in environments where the sudo helper is missing.
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
- failed to copy core
- Called register() before prepare()
- Can't create listener
- Can't create listener
- child process failed
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/00dacc6d8bfe19a7.
Report an issue: GitHub.
Appendix: source
Thrown at backend/tauri/src/core/manager.rs:52
let sudo = match Command::new("which").arg("pkexec").output() {
Ok(output) => {
if output.stdout.is_empty() {
"sudo"
} else {
"pkexec"
}
}
Err(_) => "sudo",
};
Command::new(sudo).arg("sh").arg("-c").arg(shell).output()?
};
if output.status.success() {
Ok(())
} else {
let stderr = std::str::from_utf8(&output.stderr).unwrap_or("");
anyhow::bail!("{stderr}");
}
}
#[allow(unused)]
pub fn escape(text: &str) -> Cow<'_, str> {
let bytes = text.as_bytes();
let mut owned = None;
for pos in 0..bytes.len() {
let special = match bytes[pos] {
b' ' => Some(b' '),
_ => None,
};
if let Some(s) = special {
if owned.is_none() {
owned = Some(bytes[0..pos].to_owned());
}View on GitHub (pinned to f7dbce2997)