mihomo-party-org/clash-party · error · GatewayError

unreachable

unreachable

Error message

err.message

What it means

postJson() wraps any failure from the underlying HTTP client into a GatewayError. The category is chosen by isUnreachable(err): DNS/connect failures become 'unreachable', everything else becomes 'transient', and err.message becomes the GatewayError message. So this is a network-layer failure during a gateway POST, not a gateway application error.

Source

Thrown at src/main/resolve/plugin/gateway.ts:88

  // Node 的 TLS/证书错误 code 形如 ERR_TLS_*, ERR_SSL_*, CERT_*, SELF_SIGNED_*, UNABLE_TO_*, DEPTH_ZERO_*
  return /^(ERR_TLS|ERR_SSL|CERT_|SELF_SIGNED_|UNABLE_TO_|DEPTH_ZERO_)/.test(code)
}

async function postJson(url: string, body: unknown, net: GatewayNet): Promise<RawResult> {
  let res: { status: number; body: string }
  try {
    res = await requestOnce(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body),
      timeout: net.timeout,
      maxBytes: MAX_BYTES,
      lookup: lookupFor(net),
      proxy: net.proxy
    })
  } catch (e) {
    const err = e as NodeJS.ErrnoException
    throw new GatewayError(isUnreachable(err) ? 'unreachable' : 'transient', err.message)
  }
  let json: Record<string, unknown> | undefined
  try {
    const parsed = JSON.parse(res.body)
    json =
      typeof parsed === 'object' && parsed !== null
        ? (parsed as Record<string, unknown>)
        : undefined
  } catch {
    json = undefined
  }
  return { status: res.status, json, text: res.body }
}

function classify(r: RawResult): GatewayError | null {
  if (r.status === 410 || r.json?.error === 'gateway_retired') {
    return new GatewayError('retired', 'gateway retired', r.status)
  }

View on GitHub (pinned to 911e090537)

Solutions

  1. Check network connectivity and that the gateway host is reachable (ping/curl the gateway URL).
  2. Verify the gateway hostname and port in your GatewayTarget config.
  3. Check proxy settings — a wrong net.proxy value causes unreachable errors.
  4. Classified 'unreachable': retry with backoff once connectivity is restored; this is not an app-level retry target.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight reachability check before POSTing
const u = new URL(target.gateway)
await new Promise((ok, bad) => {
  const s = require('node:net').connect(Number(u.port) || 443, u.hostname, ok)
  s.on('error', bad); s.setTimeout(5000, () => { s.destroy(); bad(new Error('timeout')) })
})

Try / catch

try {
  return await postJson(target, ep, body, dev, net)
} catch (e) {
  if (e instanceof GatewayError && e.code === 'unreachable') {
    // exponential backoff, bounded retries; surface connectivity guidance
  } else throw e
}

Prevention

When it happens

Trigger: The fetch/post to the gateway throws — DNS resolution failure, TCP connect refused/timeout, TLS error, proxy misconfiguration, or request-construction failure inside the HTTP client.

Common situations: Gateway host typo'd or offline, no internet/VPN, DNS blocked or intercepted, corporate proxy set via net.proxy unreachable, or firewall dropping the connection.

Related errors


AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30). Data as JSON: /api/errors/cd175dea61453db7. Report an issue: GitHub.