mihomo-party-org/clash-party · error

Request failed with status ${res.status}: ${url}

Error message

Request failed with status ${res.status}: ${url}

What it means

tryDownload in src/main/resolve/autoUpdater.ts:54 iterates a list of candidate download URLs (direct + proxied GitHub mirrors). Any HTTP status outside 200-299 is treated as failure: it throws `Request failed with status ${res.status}: ${url}`, which is captured into lastError and the loop continues to the next mirror. If all mirrors fail, the last such error propagates — meaning the reported status/url belongs to the final attempted source.

Source

Thrown at src/main/resolve/autoUpdater.ts:54

function buildDownloadUrls(githubUrl: string, proxyPref = ''): string[] {
  if (proxyPref === 'direct') return [githubUrl]
  if (proxyPref && proxyPref !== 'auto') return [`${proxyPref}/${githubUrl}`]
  // auto: try each proxy then fall back to direct
  return [...GITHUB_PROXIES.map((p) => `${p}/${githubUrl}`), githubUrl]
}

async function tryDownload(
  urls: string[],
  options: Parameters<typeof chromeRequest.get>[1]
): Promise<Awaited<ReturnType<typeof chromeRequest.get>>> {
  let lastError: unknown
  for (const url of urls) {
    try {
      const res = await chromeRequest.get(url, options)
      // 代理源限流/失效时会以 200 以外的状态返回错误页,必须当作失败才能继续尝试下一个源
      if (res.status < 200 || res.status >= 300) {
        throw new Error(`Request failed with status ${res.status}: ${url}`)
      }
      return res
    } catch (e) {
      lastError = e
    }
  }
  throw lastError
}

type UpdaterProxy = { protocol: 'http'; host: string; port: number } | false

// 用户关闭混合端口时配置里写的是 0(不是 undefined),解构默认值挡不住。
// 直接拿 0 去拼代理会打到 127.0.0.1:0,检查更新和下载更新都必然失败,
// 所以端口未启用时要显式走直连。
function updaterProxy(mixedPort: number): UpdaterProxy {
  return mixedPort ? { protocol: 'http', host: '127.0.0.1', port: mixedPort } : false
}

View on GitHub (pinned to 911e090537)

Solutions

  1. Retry the update later — proxy mirrors are often temporarily rate-limited (429/403)
  2. Switch or clear the configured githubProxy setting in app config to use a different/working mirror
  3. Verify the release tag and asset still exist on GitHub (404 means the asset was removed)
  4. Check network/firewall access to both direct GitHub and the proxy host
  5. If all mirrors consistently fail, inspect lastError in tryDownload logs to see which status each source returned

Example fix

// before
const res = await chromeRequest.get(deadMirrorUrl, options)
// after — skip a failing proxy by using the direct URL or a healthy mirror
const res = await chromeRequest.get('https://github.com/owner/repo/releases/download/v1.2.3/app.exe', options)
Defensive patterns

Strategy: retry

Validate before calling

// pre-check a mirror before relying on it
const probe = await fetch(mirrorUrl, { method: 'HEAD' })
if (!probe.ok) console.warn(`mirror ${mirrorUrl} unhealthy: ${probe.status}`)

Type guard

function isOkStatus(status: number): boolean {
  return status >= 200 && status < 300
}

Try / catch

try {
  const res = await tryDownload(urls, options)
  install(res)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Request failed with status')) {
    // all mirrors exhausted; surface status from message and retry later
    safeShowErrorBox('updater.downloadFailed', e.message)
  }
}

Prevention

When it happens

Trigger: chromeRequest.get returns res.status 403/429 (rate limiting), 404 (asset removed or tag renamed), or 5xx from a proxy mirror; the thrown error is either intermediate (a later mirror succeeds) or final (all urls exhausted).

Common situations: GitHub proxy sources (ghproxy-style mirrors) are rate-limited or dead and return non-2xx error pages; a release tag was deleted or renamed so the asset 404s; corporate firewalls block the proxy domain; GitHub API rate limits during version checks.

Related errors


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