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

  1. Delete the stale /tmp/<identifier>-deep-link.sock file and restart
  2. Ensure only one instance of the app runs per identifier
  3. Use Linux-style cleanup (remove_file on ConnectionRefused before binding) as done on other platforms
  4. 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

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


AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08). Data as JSON: /api/errors/a92dca6e52e338ef. Report an issue: GitHub.