Hmbown/CodeWhale · error · Error

GitHub Release asset set is stale for workflow run

Error message

GitHub Release asset set is stale for workflow run ${run.database_id || run.id}: ${stale.join("; ")}

What it means

After confirming all expected assets exist, assertReleaseAssetsFresh compares each asset's updated_at against the freshness baseline (the successful release job's started_at, falling back to run timestamps). Assets older than the baseline are considered stale and it throws listing each stale asset with its timestamp.

Solutions

  1. Delete the release (or its assets) and re-run the Release workflow so all assets are freshly built and uploaded.
  2. Ensure the release job started before asset upload timestamps (check clock skew if times are close).
  3. Never re-tag an existing version; use a new version string.

Example fix

// before
git tag -f v1.2.3 HEAD~1  # stale assets kept
// after
gh release delete v1.2.3 --cleanup-tag && git tag v1.2.3 <sha> && gh workflow run release.yml
Defensive patterns

Strategy: validation

Validate before calling

const baseline = Date.parse(run.release_job_started_at ?? run.run_started_at); const stale = expected.filter(n => Date.parse(assetByName(n).updated_at) < baseline); if (stale.length) console.error("Stale assets:", stale);

Type guard

null

Try / catch

try { verifyFreshness(); } catch (e) { if (e.message.includes("asset set is stale")) { console.error("Delete the release and re-run the Release workflow for this tag."); process.exit(1); } throw e; }

Prevention

When it happens

Trigger: An asset's updatedAt < freshnessBaseline — i.e., the release asset predates the workflow run that should have produced it, indicating leftovers from an earlier run or a re-tagged release.

Common situations: Re-tagging a version without deleting the old release, so old assets survive; manually attaching binaries built from a different commit; concurrency skipping upload while old assets remain.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/35c85117da3b3bc2. Report an issue: GitHub.

Appendix: source

Thrown at npm/codewhale/scripts/verify-release-assets.js:293

  // job baseline is unavailable.
  const baseline = run.release_job_started_at || run.run_started_at || run.created_at;
  const baselineLabel = run.release_job_started_at ? "release job start" : "workflow run start";
  const freshnessBaseline = parseGitHubTime(baseline, baselineLabel);
  const stale = [];
  for (const expected of expectedAssets) {
    const asset = assetsByName.get(expected);
    if (asset.state && asset.state !== "uploaded") {
      stale.push(`${expected} has state ${asset.state}`);
      continue;
    }
    const updatedAt = parseGitHubTime(asset.updated_at || asset.created_at, `${expected} update`);
    if (updatedAt < freshnessBaseline) {
      stale.push(`${expected} updated at ${asset.updated_at || asset.created_at}`);
    }
  }

  if (stale.length > 0) {
    throw new Error(
      `GitHub Release asset set is stale for workflow run ${run.database_id || run.id}: ${stale.join("; ")}`,
    );
  }
}

async function verifyGitHubReleaseFreshness(repo, version, expectedAssets) {
  const tag = `v${version}`;
  const tagSha = await resolveTagCommitSha(repo, tag);
  const release = await githubApi(repo, `/releases/tags/${encodeURIComponent(tag)}`);
  const run = await findReleaseWorkflowRun(repo, tag, tagSha);
  assertReleaseAssetsFresh(release, expectedAssets, run);
  console.log(
    `GitHub release asset freshness OK: ${expectedAssets.length} release assets for ${tag} were produced by run ${run.database_id || run.id} at ${tagSha.slice(0, 12)}.`,
  );
}

function parseChecksumManifest(text) {
  const checksums = new Map();

View on GitHub (pinned to 433685b202)