libnyanpasu/clash-nyanpasu · error
Can't create listener
Error message
Can't create listener
What it means
listen() binds a Unix domain socket at /tmp/{app-id}-deep-link.sock and .expects the bind to succeed, panicking with "Can't create listener" on failure. Bind fails when the path is invalid, a stale socket file exists without cleanup in a way that blocks bind, the tmp directory is unwritable, or another process owns the socket.
Source
Thrown at backend/tauri-plugin-deep-link/src/linux.rs:110
"Couldn't get file name of current executable.",
))?
.to_string_lossy()
));
remove_file(&target)?;
target.pop();
Ok(())
}
pub fn listen<F: FnMut(String) + Send + 'static>(mut handler: F) -> Result<()> {
std::thread::spawn(move || {
let addr = format!(
"/tmp/{}-deep-link.sock",
ID.get().expect("listen() called before prepare()")
);
let listener = UnixListener::bind(addr).expect("Can't create listener");
for stream in listener.incoming() {
match stream {
Ok(mut stream) => {
let mut buffer = String::new();
if let Err(io_err) = stream.read_to_string(&mut buffer) {
log::error!("Error reading incoming connection: {}", io_err.to_string());
};
handler(dbg!(buffer));
}
Err(err) => {
log::error!("Incoming connection failed: {}", err);
continue;
}
}
}
});View on GitHub (pinned to f7dbce2997)
Solutions
- Ensure only one app instance runs, or forward deep-link URLs to the existing instance instead of binding again.
- Delete the stale /tmp/{app-id}-deep-link.sock file before starting if the previous run crashed.
- Check /tmp permissions (writable by the app user) and sandbox/container mount settings.
- Shorten the app ID if the socket path exceeds ~108 characters.
- Patch the plugin to handle bind errors gracefully (return Err / retry with cleanup) instead of expect.
Example fix
// before: blind bind that panics on stale socket
let listener = UnixListener::bind(&addr).expect("Can't create listener");
// after: clean up stale socket, then bind
let _ = std::fs::remove_file(&addr); // ignore Not-Found
let listener = UnixListener::bind(&addr).expect("Can't create listener"); Defensive patterns
Strategy: validation
Validate before calling
let addr = format!("/tmp/{}-deep-link.sock", APP_ID);
let _ = std::fs::remove_file(&addr); // clear stale socket
assert!(addr.len() <= 107, "socket path too long"); Try / catch
match UnixListener::bind(&addr) { Ok(l) => ..., Err(e) if e.kind() == io::ErrorKind::AddrInUse => eprintln!("another instance running"), Err(e) => return Err(e.into()) } Prevention
- Enforce single-instance; forward URLs to the running instance.
- Remove stale socket files at startup.
- Verify /tmp is writable in your sandbox/container.
- Keep the app ID short enough for the 108-byte Unix socket path limit.
When it happens
Trigger: UnixListener::bind fails because another instance of the app already holds the deep-link socket, /tmp is not writable, a leftover socket file with wrong permissions exists at the path, or the app ID contains characters that make the path invalid/too long.
Common situations: Running a second instance of the app while the first is still alive; containers/sandboxes with read-only or restricted /tmp; crashes that left a stale socket file; very long app IDs exceeding the 108-byte Unix socket path limit.
Related errors
- Called register() before prepare()
- listen() called before prepare()
- Local socket too many crashes
- data directory not found.
- Couldn't get file name of curent executable.
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/f4a278e0515006c4.
Report an issue: GitHub.