{"record":{"id":"6018c4027f4439af","repo":"can1357/oh-my-pi","slug":"github-release-expectedtag-has-matches-length","errorCode":null,"errorMessage":"GitHub release ${expectedTag} has ${matches.length} assets named ${binaryName}","messagePattern":"GitHub release (.+?) has (.+?) assets named (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/update-cli.ts","lineNumber":214,"sourceCode":"\tif (!isRecord(release)) {\n\t\tthrow new Error(\"Invalid GitHub release metadata\");\n\t}\n\tif (release.tag_name !== expectedTag) {\n\t\tthrow new Error(`GitHub release tag mismatch: expected ${expectedTag}`);\n\t}\n\tif (release.draft !== false) {\n\t\tthrow new Error(`GitHub release ${expectedTag} is a draft, not a published release`);\n\t}\n\tif (release.prerelease !== false && !options.allowPrerelease) {\n\t\tthrow new Error(`GitHub release ${expectedTag} is a prerelease; only canary updates install prerelease assets`);\n\t}\n\tif (!Array.isArray(release.assets)) {\n\t\tthrow new Error(`GitHub release ${expectedTag} has no asset list`);\n\t}\n\n\tconst matches = release.assets.filter(asset => isRecord(asset) && asset.name === binaryName);\n\tif (matches.length !== 1) {\n\t\tthrow new Error(`GitHub release ${expectedTag} has ${matches.length} assets named ${binaryName}`);\n\t}\n\n\tconst asset = matches[0];\n\tif (!isRecord(asset) || asset.state !== \"uploaded\") {\n\t\tthrow new Error(`GitHub release asset ${binaryName} is not fully uploaded`);\n\t}\n\tif (typeof asset.size !== \"number\" || !Number.isSafeInteger(asset.size) || asset.size <= 0) {\n\t\tthrow new Error(`GitHub release asset ${binaryName} has an invalid size`);\n\t}\n\tif (typeof asset.digest !== \"string\") {\n\t\tthrow new Error(`GitHub release asset ${binaryName} has no digest`);\n\t}\n\tconst digest = /^sha256:([0-9a-f]{64})$/i.exec(asset.digest)?.[1];\n\tif (!digest) {\n\t\tthrow new Error(`GitHub release asset ${binaryName} has an unsupported digest`);\n\t}\n\n\tconst expectedUrl = `https://github.com/${REPO}/releases/download/${expectedTag}/${binaryName}`;","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/update-cli.ts#L196-L232","documentation":"After collecting assets whose `name` equals the expected platform binary name, the code requires exactly one match. Zero matches mean the binary was never uploaded for this platform; more than one means duplicate/ambiguous assets. The count is embedded in the message so the failure mode is immediately clear.","triggerScenarios":"resolveReleaseBinaryAsset filters release.assets by `asset.name === binaryName` and throws whenever matches.length !== 1 — i.e. the release has no asset with that exact name, or two or more assets share it.","commonSituations":"Running the updater on a platform whose binary was not included in the release (e.g. arm64 build missing), a release workflow re-run that uploaded the same filename twice, a typo or naming-scheme change in the CI upload step, or the user's binaryName not matching the released naming convention.","solutions":["Inspect the release's assets on https://github.com/<owner>/<repo>/releases/tags/<tag> and compare exact filenames against the expected binaryName.","If the binary is missing, re-run or fix the release upload workflow for your platform.","If duplicates exist, delete the stale duplicate asset and re-publish, or cut a new release.","Wait for the release process to finish if it is still mid-publish, then retry."],"exampleFix":"// before: release missing the platform asset (only linux-x64 uploaded)\nassets: [{ name: \"omp-linux-x64\", ... }]\n// after: upload all platform binaries\nassets: [\n  { name: \"omp-linux-x64\", ... },\n  { name: \"omp-linux-arm64\", ... },\n  { name: \"omp-darwin-arm64\", ... }\n]","handlingStrategy":"validation","validationCode":"const matching = (release.assets as { name?: unknown }[]).filter(a => a?.name === binaryName);\nif (matching.length !== 1) {\n  console.error(`Release ${tag} has ${matching.length} assets named ${binaryName}; available: ${(release.assets as { name?: unknown }[]).map(a => a?.name).join(\", \")}`);\n  process.exit(1);\n}","typeGuard":"function isUniqueAsset(assets: unknown[], binaryName: string): boolean {\n  return assets.filter(a => typeof a === \"object\" && a !== null && (a as { name?: unknown }).name === binaryName).length === 1;\n}","tryCatchPattern":"try {\n  await update();\n} catch (err) {\n  const m = err instanceof Error ? err.message : \"\";\n  if (/has \\d+ assets named /.test(m)) {\n    console.error(`Binary asset problem for your platform: ${m}. Inspect the release assets on GitHub.`);\n  } else throw err;\n}","preventionTips":["Keep release upload workflows atomic: upload all platform binaries before publishing.","Disable or clean up re-upload retries that can create duplicate asset names.","Pin CI to a naming convention and assert all expected platform filenames exist before publish."],"tags":["github-api","release-assets","update","publishing"],"backgroundTag":"release-asset-missing","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}