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
- Check network connectivity and that the gateway host is reachable (ping/curl the gateway URL).
- Verify the gateway hostname and port in your GatewayTarget config.
- Check proxy settings — a wrong net.proxy value causes unreachable errors.
- 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
- Verify gateway hostname/port and DNS resolution before deployment.
- Test proxy settings (net.proxy) — wrong proxies surface as unreachable.
- Monitor connectivity and alert on 'unreachable' GatewayErrors rather than retrying forever.
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
- Request failed with status ${res.status}: ${url}
- GitHub API error: ${error.message}
- HTTP ${response.status} ${response.statusText}
- Get device failed
- Invalid latest.yml from update source
AI-assisted analysis of mihomo-party-org/clash-party@911e090537 (2026-08-30).
Data as JSON: /api/errors/cd175dea61453db7.
Report an issue: GitHub.