Yeachan-Heo/oh-my-codex · error · Error

[native-assets] failed to download ${url} (${response.status

Error message

[native-assets] failed to download ${url} (${response.status} ${response.statusText})

What it means

A binary or archive download returned a non-OK status or had no body. This is the raw fetch inside downloadFile used to pull platform archives from the release; the message includes the failing URL and HTTP status so you can see exactly what was rejected.

Source

Thrown at src/cli/native-assets.ts:266

  return manifest;
}

function isUnavailableManifestError(error: unknown): boolean {
  if (!(error instanceof Error)) return false;
  return /\[native-assets\] failed to fetch native release manifest/i.test(error.message)
    || /fetch failed/i.test(error.message);
}

function isUnavailableArchiveError(error: unknown): boolean {
  if (!(error instanceof Error)) return false;
  return /\[native-assets\] failed to download /i.test(error.message)
    || /fetch failed/i.test(error.message);
}

async function downloadFile(url: string, destinationPath: string): Promise<void> {
  const response = await fetch(url);
  if (!response.ok || !response.body) {
    throw new Error(`[native-assets] failed to download ${url} (${response.status} ${response.statusText})`);
  }
  await mkdir(dirname(destinationPath), { recursive: true });
  await pipeline(Readable.fromWeb(response.body), createWriteStream(destinationPath));
}

async function sha256ForFile(path: string): Promise<string> {
  const hash = createHash('sha256');
  hash.update(await readFile(path));
  return hash.digest('hex');
}


const SIDECAR_SUFFIX = '.sha256';
const LOCK_SUFFIX = '.hydrate.lock';
const LOCK_WAIT_MS = 10_000;
const LOCK_RETRY_MS = 100;
const NATIVE_LOCK_WAIT_MS_ENV = 'OMX_NATIVE_LOCK_WAIT_MS';

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Open the URL in the message; if 404, confirm the release includes an asset for your platform.
  2. If 403/429, address GitHub rate limiting (wait, cache, or mirror assets internally).
  3. Pre-hydrate the cache in your base Docker image so runtime downloads are unnecessary.
  4. Point NATIVE_RELEASE_BASE_URL at an authenticated internal mirror.
Defensive patterns

Strategy: retry

Validate before calling

async function assetDownloadable(url: string): Promise<boolean> { const r = await fetch(url, { method: 'HEAD' }); return r.ok; }

Try / catch

try { await hydrateNativeBinary(); } catch (e) { if (/\[native-assets\] failed to download /.test(String(e))) { /* extract URL+status; fix proxy/rate limit/missing asset */ } throw e; }

Prevention

When it happens

Trigger: hydrateNativeBinary fetching an asset.download_url that returns 404 (asset missing for that platform), 403 (rate limit / private repo without auth), or a proxy/network failure producing a non-OK response.

Common situations: A platform archive (e.g. linux-arm64 musl) missing from the release; GitHub rate limits in CI; private repos where the asset URL requires authentication; expired signed URLs from a mirror.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/f296d3890e25d7e4. Report an issue: GitHub.