can1357/oh-my-pi · error · Error
GitHub release asset ${binaryName} has an unexpected downloa
Error message
GitHub release asset ${binaryName} has an unexpected download URL What it means
The updater computes the canonical download URL (`https://github.com/<REPO>/releases/download/<tag>/<binaryName>`) and requires the asset's `browser_download_url` to match exactly. A mismatch means the asset would be served from somewhere other than the expected path — possibly a redirect, mirror, or spoofed entry — so the update aborts as a supply-chain safeguard.
Source
Thrown at packages/coding-agent/src/cli/update-cli.ts:234
const asset = matches[0];
if (!isRecord(asset) || asset.state !== "uploaded") {
throw new Error(`GitHub release asset ${binaryName} is not fully uploaded`);
}
if (typeof asset.size !== "number" || !Number.isSafeInteger(asset.size) || asset.size <= 0) {
throw new Error(`GitHub release asset ${binaryName} has an invalid size`);
}
if (typeof asset.digest !== "string") {
throw new Error(`GitHub release asset ${binaryName} has no digest`);
}
const digest = /^sha256:([0-9a-f]{64})$/i.exec(asset.digest)?.[1];
if (!digest) {
throw new Error(`GitHub release asset ${binaryName} has an unsupported digest`);
}
const expectedUrl = `https://github.com/${REPO}/releases/download/${expectedTag}/${binaryName}`;
if (asset.browser_download_url !== expectedUrl) {
throw new Error(`GitHub release asset ${binaryName} has an unexpected download URL`);
}
return {
url: expectedUrl,
size: asset.size,
digest: `sha256:${digest.toLowerCase()}`,
};
}
async function getReleaseBinaryAsset(
expectedVersion: string,
binaryName: string,
fetchImpl: Fetch = fetch,
githubToken: string | undefined = $env.GITHUB_TOKEN || $env.GH_TOKEN,
allowPrerelease = false,
): Promise<ReleaseBinaryAsset> {
const tag = `v${expectedVersion}`;
const headers: Record<string, string> = {View on GitHub (pinned to 9690622007)
Solutions
- Compare the asset's browser_download_url in the API response against the expected https://github.com/<owner>/<repo>/releases/download/<tag>/<name> pattern.
- Remove or bypass any proxy/mirror rewriting download URLs and retry.
- If the repo was transferred/renamed, update REPO in update-cli.ts or follow redirects properly.
- Fix test stubs to build the URL with the same REPO/tag/binaryName the resolver expects.
Example fix
// before (stub URL for wrong repo)
browser_download_url: "https://github.com/fork/omp/releases/download/v1.2.3/omp-linux-x64"
// after
browser_download_url: `https://github.com/${REPO}/releases/download/v1.2.3/omp-linux-x64` Defensive patterns
Strategy: validation
Validate before calling
const expectedUrl = `https://github.com/${REPO}/releases/download/${tag}/${binaryName}`;
const asset = release.assets?.find(a => a?.name === binaryName);
if (asset?.browser_download_url !== expectedUrl) {
throw new Error(`Download URL mismatch: expected ${expectedUrl}, got ${asset?.browser_download_url}`);
} Type guard
function hasExpectedUrl(asset: unknown, expectedUrl: string): boolean {
return (asset as { browser_download_url?: unknown })?.browser_download_url === expectedUrl;
} Try / catch
try {
await update();
} catch (err) {
if (err instanceof Error && err.message.includes("unexpected download URL")) {
console.error("Asset download URL does not match the canonical release path; possible mirror/rewrite. Bypass proxies and retry.");
} else throw err;
} Prevention
- Pin updates to canonical github.com download URLs; treat rewrites as hostile.
- Disable response-rewriting proxies for api.github.com and github.com downloads.
- Update REPO constants after repo transfers/renames.
When it happens
Trigger: resolveReleaseBinaryAsset throws when `asset.browser_download_url !== expectedUrl` for the uniquely matched asset — the URL points to a different repo, tag, host, or filename.
Common situations: A repository fork or rename making GitHub return adjusted URLs, a proxy/enterprise mirror rewriting URLs, test stubs with wrong URLs, or assets uploaded to a differently-named release while the tag check passed.
Related errors
- GitHub release ${expectedTag} has no asset list
- GitHub release ${expectedTag} has ${matches.length} assets n
- GitHub release asset ${binaryName} is not fully uploaded
- GitHub release asset ${binaryName} has an invalid size
- GitHub release asset ${binaryName} has no digest
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b9b8cc283a87497d.
Report an issue: GitHub.