can1357/oh-my-pi · error · Error

Failed to fetch GitHub release metadata: ${response.statusTe

Error message

Failed to fetch GitHub release metadata: ${response.statusText}

What it means

Thrown by getReleaseBinaryAsset in packages/coding-agent/src/cli/update-cli.ts when the GitHub REST releases API responds with a non-OK status that is not the already-handled 403/429 rate-limit case. The updater needs release metadata (assets, digests) to locate the correct binary; without a 2xx response it cannot proceed. The HTTP statusText is embedded so the developer can see why GitHub rejected the request.

Source

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

	try {
		response = await fetchImpl(`${GITHUB_API}/repos/${REPO}/releases/tags/${encodeURIComponent(tag)}`, {
			headers,
			signal: withTimeoutSignal(RELEASE_METADATA_TIMEOUT_MS),
		});
	} catch (err) {
		if (isTimeoutError(err)) {
			throw new Error("Timed out fetching GitHub release metadata after 30s", { cause: err });
		}
		if (isUnsupportedProxyError(err)) throw new Error(unsupportedProxyMessage(), { cause: err });
		throw err;
	}
	if ((response.status === 403 && !githubToken) || response.status === 429) {
		throw new Error(
			"GitHub API rate limit exceeded while fetching release metadata; retry later or set GITHUB_TOKEN or GH_TOKEN",
		);
	}
	if (!response.ok) {
		throw new Error(`Failed to fetch GitHub release metadata: ${response.statusText}`);
	}

	return resolveReleaseBinaryAsset(await response.json(), tag, binaryName, { allowPrerelease });
}

export interface VerifiedBinaryDownloadOptions {
	url: string;
	targetPath: string;
	expectedSize: number;
	expectedDigest: string;
	fetchImpl?: Fetch;
}

/**
 * Download a binary and verify its GitHub-reported size and SHA-256 digest.
 */
export async function downloadVerifiedBinary(options: VerifiedBinaryDownloadOptions): Promise<void> {
	const fetchImpl = options.fetchImpl ?? fetch;

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the release/tag actually exists on the repo the updater targets (e.g. check https://github.com/<owner>/<repo>/releases).
  2. If GITHUB_TOKEN or GH_TOKEN is set, validate it: `gh api user` or `curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com` — replace or unset if invalid.
  3. If the error is transient (5xx), wait and retry the update later.
  4. Check https://www.githubstatus.com for ongoing GitHub API incidents.

Example fix

// before: expired token in shell profile
export GITHUB_TOKEN=ghp_oldexpiredtoken
// after
unset GITHUB_TOKEN  # or export GITHUB_TOKEN=$(gh auth token)
Defensive patterns

Strategy: try-catch

Validate before calling

const token = process.env.GITHUB_TOKEN ?? process.env.GH_TOKEN;
if (token) {
  const res = await fetch("https://api.github.com/user", { headers: { Authorization: `Bearer ${token}` } });
  if (!res.ok) console.warn("GITHUB_TOKEN is invalid; unset it before updating");
}

Type guard

function isGitHubApiFailure(err: unknown): err is Error & { message: string } {
  return err instanceof Error && err.message.startsWith("Failed to fetch GitHub release metadata");
}

Try / catch

try {
  await runUpdate();
} catch (err) {
  if (isGitHubApiFailure(err)) {
    // inspect statusText in err.message; wait for GitHub incident or fix GITHUB_TOKEN, then retry
  } else throw err;
}

Prevention

When it happens

Trigger: Any non-ok GitHub API response during `omp update`: 404 when the resolved release tag or release object does not exist, 401 when GITHUB_TOKEN/GH_TOKEN is set but invalid or expired, 5xx when GitHub is having an incident, or 403 with a token set (rate-limit-with-token branch only handles 403 without a token).

Common situations: Running an update against a fork or private repo where the release is not published; a stale/expired GitHub PAT in the environment; GitHub status degradation; requesting a --canary tag that was deleted.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


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