{"record":{"id":"288787cfc815d2e7","repo":"Hmbown/CodeWhale","slug":"github-release-is-missing-required-release-asset-s-missing","errorCode":null,"errorMessage":"GitHub Release is missing required release asset(s): ${missing.join(\", \")}","messagePattern":"GitHub Release is missing required release asset\\(s\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"npm/codewhale/scripts/verify-release-assets.js","lineNumber":270,"sourceCode":"  throw new Error(\n    `No successful asset-publishing job found in release.yml workflow runs for ${tag} at ${tagSha}. ` +\n      \"Repair the Release workflow before publishing npm.\",\n  );\n}\n\nfunction parseGitHubTime(value, label) {\n  const timestamp = Date.parse(value);\n  if (!Number.isFinite(timestamp)) {\n    throw new Error(`GitHub ${label} timestamp is invalid: ${value}`);\n  }\n  return timestamp;\n}\n\nfunction assertReleaseAssetsFresh(release, expectedAssets, run) {\n  const assetsByName = new Map((release.assets || []).map((asset) => [asset.name, asset]));\n  const missing = expectedAssets.filter((asset) => !assetsByName.has(asset));\n  if (missing.length > 0) {\n    throw new Error(`GitHub Release is missing required release asset(s): ${missing.join(\", \")}`);\n  }\n\n  // #5429: compare against the successful release job's started_at when the\n  // run record carries it; fall back to the run-level timestamp only when a\n  // job baseline is unavailable.\n  const baseline = run.release_job_started_at || run.run_started_at || run.created_at;\n  const baselineLabel = run.release_job_started_at ? \"release job start\" : \"workflow run start\";\n  const freshnessBaseline = parseGitHubTime(baseline, baselineLabel);\n  const stale = [];\n  for (const expected of expectedAssets) {\n    const asset = assetsByName.get(expected);\n    if (asset.state && asset.state !== \"uploaded\") {\n      stale.push(`${expected} has state ${asset.state}`);\n      continue;\n    }\n    const updatedAt = parseGitHubTime(asset.updated_at || asset.created_at, `${expected} update`);\n    if (updatedAt < freshnessBaseline) {\n      stale.push(`${expected} updated at ${asset.updated_at || asset.created_at}`);","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/npm/codewhale/scripts/verify-release-assets.js#L252-L288","documentation":"assertReleaseAssetsFresh first checks that every expected asset name is present on the GitHub Release; if any are absent it throws listing the missing names. The verifier treats an incomplete release as unsafe to publish against.","triggerScenarios":"verifyGitHubReleaseFreshness is called and the Release's assets array lacks one or more of the expected asset names (checked via assetsByName.has).","commonSituations":"Release workflow partially failed so some platform binaries were never uploaded; assets manually deleted from the release; version mismatch between npm and the GitHub release (expected names differ).","solutions":["Compare the release's asset list against the expected names; re-run the Release workflow to re-upload missing assets.","Confirm resolveBinaryVersion() matches the version the release was built for.","Check the release workflow's upload steps for silent failures or renamed artifacts."],"exampleFix":"// workflow: re-upload missing assets\ngh release upload v1.2.3 dist/codewhale-linux-x64.tar.gz --clobber","handlingStrategy":"validation","validationCode":"const names = new Set((release.assets ?? []).map(a => a.name)); const missing = expectedAssets.filter(a => !names.has(a)); if (missing.length) console.error(\"Missing assets:\", missing);","typeGuard":"null","tryCatchPattern":"try { await verifyGitHubReleaseFreshness(repo, version, expected); } catch (e) { if (e.message.includes(\"missing required release asset\")) { console.error(\"Re-run the Release workflow to upload all assets.\"); process.exit(1); } throw e; }","preventionTips":["Verify the release asset list right after the Release workflow finishes","Keep asset naming generated from one source of truth","Never hand-edit published releases"],"tags":["release","github","assets","missing-file"],"backgroundTag":"resource-not-found","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}