can1357/oh-my-pi · error · Error

GitHub release asset ${binaryName} has no digest

Error message

GitHub release asset ${binaryName} has no digest

What it means

The updater verifies downloads against the asset's sha256 digest, which GitHub exposes on the asset record as a `digest` string. If the field is absent, integrity verification is impossible, so the update is refused rather than installing an unverified binary.

Source

Thrown at packages/coding-agent/src/cli/update-cli.ts:225

	}
	if (!Array.isArray(release.assets)) {
		throw new Error(`GitHub release ${expectedTag} has no asset list`);
	}

	const matches = release.assets.filter(asset => isRecord(asset) && asset.name === binaryName);
	if (matches.length !== 1) {
		throw new Error(`GitHub release ${expectedTag} has ${matches.length} assets named ${binaryName}`);
	}

	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()}`,
	};
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Confirm you are sending the supported API version header (X-GitHub-Api-Version: 2022-11-28) and refetch.
  2. Check the asset in the GitHub API response — if digest is absent, re-upload the asset so GitHub computes a digest.
  3. Retry later: digest population can briefly lag upload on very fresh releases.
  4. Avoid proxies/interceptors that rewrite the response body.
Defensive patterns

Strategy: validation

Validate before calling

const asset = release.assets?.find(a => a?.name === binaryName);
if (typeof asset?.digest !== "string") {
  console.warn("Asset has no digest; refusing unverified download.");
  process.exit(1);
}

Type guard

function hasDigest(asset: unknown): asset is { digest: string } {
  return typeof (asset as { digest?: unknown })?.digest === "string";
}

Try / catch

try {
  await update();
} catch (err) {
  if (err instanceof Error && err.message.includes("has no digest")) {
    console.error("GitHub did not provide a checksum for this asset; update refused for safety. Re-upload the asset or retry later.");
  } else throw err;
}

Prevention

When it happens

Trigger: resolveReleaseBinaryAsset throws when the matched asset has `typeof asset.digest !== "string"` — the digest field is missing, null, or a non-string value.

Common situations: Releases created before GitHub started populating asset digests, custom upload tooling or API-created assets without digests, proxies stripping fields, or older pinned API versions that predate the digest field.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/55b27ae84d8f2136. Report an issue: GitHub.