libnyanpasu/clash-nyanpasu · error

DIRECT is missing in /proxies

Error message

DIRECT is missing in /proxies

What it means

Thrown by `Proxies::from_responses` when the `/proxies` API response from the Clash/Mihomo core does not contain the built-in `DIRECT` proxy entry. The parser assumes every core always reports the built-in `DIRECT`/`REJECT`/`GLOBAL` nodes and destructures them with `ok_or`; a missing entry means the response is not a well-formed proxies payload, so the library fails instead of producing a Proxies struct with a hole in it.

Source

Thrown at backend/tauri/src/core/clash/proxies.rs:123

                .filter(|(_k, v)| {
                    matches!(
                        v.vehicle_type,
                        api::VehicleType::Http | api::VehicleType::File
                    )
                })
                .collect()
        };

        // 2. Map every provider-owned proxy by name. Mihomo 1.19.28 no longer
        // includes these nodes in /proxies, so their metadata must come from
        // /providers/proxies.
        let provider_map = provider_proxy_map(&providers_proxies);
        let generate_item = |name: &str| resolve_proxy(name, &inner_proxies, &provider_map);

        let global = inner_proxies.get("GLOBAL");
        let direct = inner_proxies
            .get("DIRECT")
            .ok_or(anyhow::anyhow!("DIRECT is missing in /proxies"))?
            .clone(); // It should be always exists
        let reject = inner_proxies
            .get("REJECT")
            .ok_or(anyhow::anyhow!("REJECT is missing in /proxies"))?
            .clone(); // It should be always exists

        // 3. generate the proxies groups
        let groups: Vec<ProxyGroupItem> = match global {
            Some(api::ProxyItem { all: Some(all), .. }) => {
                let all = all.clone();
                all.into_iter()
                    .filter(|name| {
                        matches!(
                            inner_proxies.get(name),
                            Some(api::ProxyItem { all: Some(_), .. })
                        )
                    })
                    .map(|name| {

View on GitHub (pinned to f7dbce2997)

Solutions

  1. Verify the core is running and the external controller URL/port is correct before fetching /proxies.
  2. Inspect the raw /proxies response (curl the controller endpoint) and confirm it contains "DIRECT".
  3. Retry after the core finishes starting; treat a missing DIRECT as a transient not-ready signal.
  4. Check for a core version/fork that deviates from the standard API and update or switch cores.

Example fix

// before
let proxies = Proxies::from_responses(proxies_res, providers_res)?;
// after
if !proxies_res.proxies.contains_key("DIRECT") {
    anyhow::bail!("core /proxies response is not ready or malformed (missing DIRECT)");
}
let proxies = Proxies::from_responses(proxies_res, providers_res)?;
Defensive patterns

Strategy: validation

Validate before calling

if !proxies_res.proxies.contains_key("DIRECT") {
    anyhow::bail!("core /proxies not ready: missing DIRECT");
}

Type guard

fn proxies_look_well_formed(res: &api::ProxiesRes) -> bool {
    ["DIRECT", "REJECT"].iter().all(|k| res.proxies.contains_key(*k))
}

Try / catch

match Proxies::from_responses(proxies_res, providers_res) {
    Ok(p) => p,
    Err(e) if e.to_string().contains("DIRECT is missing") => {
        // treat as core-not-ready; retry after delay
        anyhow::bail!("core not ready, retry /proxies later: {e}")
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `Proxies::from_responses(proxies_res, providers_res)` where `proxies_res.proxies` (deserialized from the core's `GET /proxies`) lacks a key literally named `"DIRECT"` — e.g. the endpoint returned an error object, a partial/empty map, or a non-standard core/modified API.

Common situations: Core not fully started or shutting down so /proxies returns an empty/partial map; pointing the client at the wrong port or a different service that speaks a different API; an external controller behind a proxy/CDN that rewrites the response; a core version or fork whose /proxies omits built-ins; deserializing the wrong endpoint body into ProxiesRes.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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