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

HTTP ${response.status} ${response.statusText}

Error message

HTTP ${response.status} ${response.statusText}

What it means

downloadGitHubAsset uses chromeRequest, which resolves for ANY HTTP status (it does not reject on 4xx/5xx). So this explicit check throws 'HTTP <status> <statusText>' for non-2xx responses. Without it, a mirror's 404/502 HTML error page would be silently written to the mihomo core binary. The code then logs a warning and tries the next mirror candidate.

Source

Thrown at src/main/utils/github.ts:152

 * 下载 GitHub Release 资产
 * @param url 下载 URL
 * @param outputPath 输出路径
 */
async function downloadGitHubAsset(url: string, outputPath: string): Promise<void> {
  const { githubProxy = '' } = await getAppConfig()
  const urls = buildDownloadUrls(url, githubProxy)
  let lastError: unknown
  for (const candidate of urls) {
    try {
      log.debug(`Downloading asset from ${candidate}`)
      const response = await chromeRequest.get(candidate, {
        responseType: 'arraybuffer',
        timeout: 30000
      })
      // chromeRequest 对任何状态码都 resolve,所以这里必须自己判断。否则镜像返回的
      // 404/502 错误页会被当成下载成功写进内核文件,而且直接 return、不再尝试后续镜像。
      if (response.status < 200 || response.status >= 300) {
        throw new Error(`HTTP ${response.status} ${response.statusText}`)
      }
      await writeFile(outputPath, Buffer.from(response.data as Buffer))
      log.debug(`Successfully downloaded asset to ${outputPath}`)
      return
    } catch (error) {
      log.warn(`Download failed from ${candidate}, trying next`, error)
      lastError = error
    }
  }
  log.error(`Failed to download asset from all sources`, lastError)
  throw lastError instanceof Error
    ? new Error(`Download error: ${lastError.message}`)
    : new Error('Failed to download core file')
}

/**
 * 安装特定版本的 mihomo 核心
 * @param version 版本号

View on GitHub (pinned to 911e090537)

Solutions

  1. Retry the install — the code already iterates to the next mirror; persistent failure means all mirrors are affected.
  2. Verify the release tag exists and has the expected asset on github.com/MetaCubeX/mihomo/releases.
  3. Choose a different version, or wait until the mirror/CDN recovers if 5xx.
  4. Check the requested version string for typos (an invalid tag yields 404 for every asset).
  5. Inspect the response status in the log line 'Download failed from <candidate>, trying next' to distinguish 404 (wrong tag) from 5xx (mirror down).

Example fix

// before: old tag with removed assets fails on every mirror
await installSpecificMihomoCore('v1.18.0')
// after: validate the tag resolves before downloading
const tags = await fetchMihomoTags()
if (!tags.some((t) => t.name === 'v1.18.0')) {
  throw new Error(`Version v1.18.0 not available; latest is ${tags[0]?.name}`)
}
await installSpecificMihomoCore('v1.18.0')
Defensive patterns

Strategy: retry

Validate before calling

// HEAD the asset URL first to see the status before downloading the body
const head = await fetch(assetUrl, { method: 'HEAD' })
if (!head.ok) {
  throw new Error(`Asset not downloadable: HTTP ${head.status}; pick another mirror or version`)
}

Try / catch

try {
  await installSpecificMihomoCore(version)
} catch (e) {
  const m = String(e).match(/HTTP (\d+)/)
  if (m && (+m[1] === 404 || +m[1] >= 500)) {
    await retryWithBackoff(() => installSpecificMihomoCore(version), { attempts: 3 })
  } else {
    throw e
  }
}

Prevention

When it happens

Trigger: installMihomoCore -> downloadGitHubAsset where a mirror/CDN (or GitHub itself) returns 404 (asset/tag removed), 502/503 (mirror proxy down), or 429 (rate limited) for the release asset URL.

Common situations: Downloading an old mihomo version whose release assets were deleted; GitHub mirror (ghproxy-style) temporarily down or blocking; requesting a prerelease tag that has no packaged assets; network middleboxes returning error pages with 200 — handled separately since only non-2xx throws here.

Related errors


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