libnyanpasu/clash-nyanpasu · critical

Invalid identifier

Error message

Invalid identifier

What it means

In `prepare()`, the app identifier string is validated with interprocess-local-socket's `to_ns_name::<GenericNamespaced>()`, which rejects names that are not valid namespaced identifiers (empty, too long, or containing forbidden characters). The library `.expect()`s success because the identifier is a compile-time/app-level constant that is assumed valid. When it is not, the panic 'Invalid identifier' aborts instance startup before any socket work begins.

Solutions

  1. Fix the application identifier in tauri.conf.json so it is a valid namespaced name: non-empty, reasonably short, lowercase alphanumeric with dots or dashes (e.g. com.example.app).
  2. Validate the identifier before calling prepare(): `identifier.to_ns_name::<GenericNamespaced>()` in a Result context, or check length and character set yourself.
  3. Ensure prepare() receives the same fixed identifier used at primary-instance setup (`listen`), not a trimmed, URL-decoded, or user-malleable variant.

Example fix

// before
deep_link::prepare(&config.custom_id); // custom_id may be empty/invalid
// after
let name = interprocess::local_socket::GenericNamespaced::to_ns_name(&config.custom_id)
    .expect("app identifier must be a valid namespaced name");
deep_link::prepare(config.custom_id.as_str());
Defensive patterns

Strategy: validation

Validate before calling

use interprocess::local_socket::{GenericNamespaced, ToNsName};
pub fn is_valid_identifier(id: &str) -> bool {
    !id.is_empty()
        && id.len() <= 100
        && id.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '-' | '_'))
        && id.to_ns_name::<GenericNamespaced>().is_ok()
}

Try / catch

// Rust panics, not catchable like exceptions; validate before calling
assert!(is_valid_identifier(APP_IDENTIFIER), "invalid deep-link identifier: {APP_IDENTIFIER}");
deep_link::prepare(APP_IDENTIFIER);

Prevention

When it happens

Trigger: Calling `deep_link::prepare(identifier)` with an identifier that fails `GenericNamespaced` validation: an empty string, a name exceeding the platform length limit (typically 104 bytes on Unix-like namespace rules), or a name containing characters such as `/`, `\`, or other non-allowed characters.

Common situations: A misconfigured tauri.conf.json `identifier` (e.g. left as the default placeholder, contains uppercase/slashes, or is empty); passing a user-supplied or dynamically built string instead of a fixed app identifier; a refactor that changed the identifier format and broke namespace rules.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

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

                        }
                        Err(e) => {
                            log::error!("Error accepting connection: {e}");
                        }
                    }
                }
                CRASH_COUNT.fetch_add(1, Ordering::Release);
                let _ = listen(handler);
            });
    });

    Ok(())
}

#[inline(never)]
pub fn prepare(identifier: &str) {
    let name: Name = identifier
        .to_ns_name::<GenericNamespaced>()
        .expect("Invalid identifier");

    tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .expect("failed to create tokio runtime")
        .block_on(async move {
            for _ in 0..3 {
                match LocalSocketStream::connect(name.clone()).await {
                    Ok(conn) => {
                        // We are the secondary instance.
                        // Prep to activate primary instance by allowing another process to take focus.

                        // A workaround to allow AllowSetForegroundWindow to succeed - press a key.
                        // This was originally used by Chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=837796
                        // dummy_keypress();

                        // let primary_instance_pid = conn.peer_pid().unwrap_or(ASFW_ANY);
                        // unsafe {

View on GitHub (pinned to f7dbce2997)