libnyanpasu/clash-nyanpasu · critical
failed to start server
Error message
failed to start server
What it means
During Tauri app setup, the internal server (server::run) is started on a background thread; if it returns an error the .expect panics with 'failed to start server'. The server is essential (IPC/services depend on it), so the library treats a failed bind/start as fatal.
Source
Thrown at backend/tauri/src/lib.rs:333
&["clash-nyanpasu", "clash"],
move |request| {
log::info!(target: "app", "scheme request received: {:?}", request);
resolve::create_window(&handle.clone()); // create window if not exists
while !is_window_opened() {
log::info!(target: "app", "waiting for window open");
std::thread::sleep(std::time::Duration::from_millis(100));
}
log_err!(
crate::ipc::SchemeRequestReceivedEvent { url: request }.emit(&handle),
"failed to emit scheme-request-received event"
);
}
));
std::thread::spawn(move || {
nyanpasu_utils::runtime::block_on(async move {
server::run(*server::SERVER_PORT)
.await
.expect("failed to start server");
});
});
Ok(())
});
let app = builder
.build(tauri::generate_context!())
.expect("error while running tauri application");
app.run(|app_handle, e| match e {
tauri::RunEvent::ExitRequested { api, code, .. } if code.is_none() => {
api.prevent_exit();
}
tauri::RunEvent::ExitRequested { .. } => {
utils::help::cleanup_processes(app_handle);
}
tauri::RunEvent::WindowEvent { label, event, .. } if label == "main" => match event {
tauri::WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
core::tray::on_scale_factor_changed(scale_factor);View on GitHub (pinned to f7dbce2997)
Solutions
- Check what occupies the port (netstat) and kill the stale process, or free the port
- Use port 0 / a fallback port if the fixed port is taken, and persist the chosen port
- Detect an already-running instance first and forward activation to it instead of binding
- Add error propagation/logging before the expect to identify the underlying bind error
Example fix
// before
server::run(*server::SERVER_PORT).await.expect("failed to start server");
// after
if let Err(e) = server::run(*server::SERVER_PORT).await {
log::error!("server failed to start: {e}");
} Defensive patterns
Strategy: retry
Validate before calling
use std::net::TcpListener;
fn port_free(port: u16) -> bool {
TcpListener::bind(("127.0.0.1", port)).is_ok()
}
// call before starting the app; if !port_free(SERVER_PORT), abort or pick fallback Try / catch
match server::run(*server::SERVER_PORT).await {
Ok(()) => {},
Err(e) => log::error!("server start failed: {e}"), // surface bind error instead of panic
} Prevention
- Ensure previous instances exit cleanly and release the port
- Support a fallback port when the configured port is occupied
- Check for a running single instance before binding
When it happens
Trigger: server::run(*SERVER_PORT) fails — usually because SERVER_PORT is already bound by another process or a leftover instance of the app, or the async runtime inside the spawned thread fails to drive the server.
Common situations: Previous instance didn't shut down and still holds the port; two app instances racing for the same fixed port; firewall/AV blocking the bind; port conflict with another local service.
Related errors
- error while running tauri application
- Local socket too many crashes
- Failed to register window class: {err}
- invalid url
- should never drop oneshot tx
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/68f0a854a4abadc1.
Report an issue: GitHub.