libnyanpasu/clash-nyanpasu · error
Can't create listener
Error message
Can't create listener
What it means
In debug builds, listen() spawns a thread that binds a Unix domain socket at /tmp/<id>-deep-link.sock; UnixListener::bind().expect() panics if the bind fails. Typical causes are a stale socket file from a crashed previous instance or a path/permission problem.
Source
Thrown at backend/tauri-plugin-deep-link/src/macos.rs:152
}
unsafe {
let event_manager: Retained<AnyObject> =
msg_send_id![class!(NSAppleEventManager), sharedAppleEventManager];
let handler = Handler::new();
let handler_boxed = Box::into_raw(Box::new(handler));
let _: () = msg_send![&event_manager,
setEventHandler: &**handler_boxed
andSelector: sel!(handleEvent:withReplyEvent:)
forEventClass:EVENT_CLASS
andEventID:EVENT_GET_URL];
}
#[cfg(debug_assertions)]
std::thread::spawn(move || {
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());
};
let mut cb = HANDLER.get().unwrap().lock().unwrap();
cb(buffer);
}
Err(err) => {
log::error!("Incoming connection failed: {}", err);
continue;
}
}
}View on GitHub (pinned to f7dbce2997)
Solutions
- Delete the stale /tmp/<identifier>-deep-link.sock file and restart
- Ensure only one instance of the app runs per identifier
- Use Linux-style cleanup (remove_file on ConnectionRefused before binding) as done on other platforms
- Verify /tmp is writable in your environment
Example fix
// before
let listener = UnixListener::bind(addr).expect("Can't create listener");
// after
let _ = std::fs::remove_file(&addr); // clean stale socket
let listener = UnixListener::bind(addr).expect("Can't create listener"); Defensive patterns
Strategy: fallback
Validate before calling
let addr = format!("/tmp/{}-deep-link.sock", ID.get().expect("prepare() first"));
if std::path::Path::new(&addr).exists() { let _ = std::fs::remove_file(&addr); } Try / catch
match UnixListener::bind(&addr) {
Ok(l) => serve(l),
Err(e) if e.kind() == std::io::ErrorKind::AddrInUse => {
let _ = std::fs::remove_file(&addr);
serve(UnixListener::bind(&addr).expect("bind after cleanup"));
}
Err(e) => panic!("bind failed: {e}"),
} Prevention
- Remove stale socket files before binding (like the linux.rs ConnectionRefused cleanup)
- Run only one instance per identifier
- Check /tmp permissions in sandboxes/CI
When it happens
Trigger: Previous instance crashed without removing the socket file (bind fails with EADDRINUSE); another process holds the path; /tmp unwritable or full; two instances of the same identifier racing to bind.
Common situations: Debug sessions after an app crash leaving the .sock behind; running multiple copies of the dev app simultaneously; container/sandbox environments where /tmp is restricted.
Related errors
- URL event received before prepare() was called
- listen() called before prepare()
- prepare() called more than once with different identifiers.
- Can't create listener
- Handler was already set
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/a92dca6e52e338ef.
Report an issue: GitHub.