libnyanpasu/clash-nyanpasu · error
listen() called before prepare()
Error message
listen() called before prepare()
What it means
listen() on Windows converts the identifier from the ID OnceCell into a local-socket name. If prepare() was not called first, ID.get() returns None and this expect() panics. It enforces the prepare() -> listen() lifecycle order.
Source
Thrown at backend/tauri-plugin-deep-link/src/windows.rs:82
let base = Path::new("Software").join("Classes").join(scheme);
hkcu.delete_subkey_all(base)?;
}
Ok(())
}
static CRASH_COUNT: AtomicU16 = AtomicU16::new(0);
pub fn listen<F: FnMut(String) + Send + 'static>(mut handler: F) -> Result<()> {
if CRASH_COUNT.load(Ordering::Acquire) > 5 {
panic!("Local socket too many crashes");
}
std::thread::spawn(move || {
let name = ID
.get()
.expect("listen() called before prepare()")
.as_str()
.to_ns_name::<GenericNamespaced>()
.unwrap();
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("failed to create tokio runtime")
.block_on(async move {
let sdsf = "D:(A;;GA;;;WD)".to_wtf_16().unwrap();
let sd = SecurityDescriptor::deserialize(&sdsf).expect("Failed to deserialize SD");
let listener = ListenerOptions::new()
.name(name)
.nonblocking(ListenerNonblockingMode::Both)
.security_descriptor(sd)
.create_tokio()
.expect("Can't create listener");
loop {View on GitHub (pinned to f7dbce2997)
Solutions
- Ensure prepare(identifier) runs before listen() on every startup path
- Centralize deep-link init (prepare + listen) in one function
- Add an assertion/early check that identifier config is present before starting deep-link handling
Example fix
// before
listen(handler)?;
// after
prepare("com.example.app");
listen(handler)?; Defensive patterns
Strategy: validation
Validate before calling
assert!(ID.get().is_some(), "call prepare() before listen()");
Type guard
fn is_prepared() -> bool { ID.get().is_some() } Prevention
- Audit all listen() call sites for a preceding prepare()
- Centralize deep-link initialization
- Test each startup path (normal, single-instance handoff, tests)
When it happens
Trigger: listen() invoked before prepare(); a second registration path calling listen() without prepare(); single-instance handoff code executing before plugin setup.
Common situations: App bootstrap ordering mistakes; two listen() call sites where one path lacks prepare(); dev/test harnesses skipping plugin initialization.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- register() called before prepare()
- prepare() called more than once with different identifiers.
- URL event received before prepare() was called
- listen() called before prepare()
- prepare() called more than once with different identifiers.
AI-assisted analysis of libnyanpasu/clash-nyanpasu@f7dbce2997 (2026-09-08).
Data as JSON: /api/errors/d407ee7f4b7b663b.
Report an issue: GitHub.