libnyanpasu/clash-nyanpasu · warning

Failed to deserialize SD

Error message

Failed to deserialize SD

What it means

listen() deserializes the hardcoded security descriptor string "D:(A;;GA;;;WD)" with SecurityDescriptor::deserialize().expect(). Since the input is a compile-time constant, this panic should be impossible; it indicates a corrupted/misbehaving windows-rs security-descriptor implementation or binary tampering.

Source

Thrown at backend/tauri-plugin-deep-link/src/windows.rs:92

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 {
                    match listener.accept().await {
                        Ok(conn) => {
                            let (rx, mut tx) = conn.split();
                            let mut reader = BufReader::new(rx);
                            let mut buf = String::new();
                            if let Err(e) = reader.read_line(&mut buf).await {
                                log::error!("Error reading from connection: {e}");
                                continue;
                            }
                            buf.pop();

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Keep the SDDL string "D:(A;;GA;;;WD)" unchanged
  2. If customizing permissions, validate the SDDL syntax carefully before deserializing
  3. Pin a windows-rs version known to parse the descriptor correctly

Example fix

// before
let sdsf = "D:(GA;;;WD)".to_wtf_16().unwrap(); // missing (A;;...) -> parse failure
// after
let sdsf = "D:(A;;GA;;;WD)".to_wtf_16().unwrap(); // valid SDDL
Defensive patterns

Strategy: validation

Validate before calling

// validate SDDL before deserializing
let sddl = "D:(A;;GA;;;WD)";
debug_assert!(sddl.starts_with("D:(A;;") && sddl.ends_with("WD)"), "unexpected SDDL template");

Try / catch

let sd = SecurityDescriptor::deserialize(&sdsf)
    .expect("Failed to deserialize SD: SDDL string must remain 'D:(A;;GA;;;WD)'");

Prevention

When it happens

Trigger: Effectively unreachable with the current constant string; could fire only if the SDDL string was changed to an invalid form or the windows crate's SDDL parser fails unexpectedly.

Common situations: Modifying the SDDL string to a custom descriptor with a syntax error; unusual windows-rs crate version regressions in SDDL parsing.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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