{"record":{"id":"7fc736b899b2446a","repo":"can1357/oh-my-pi","slug":"github-release-expectedtag-is-a-prerelease-onl","errorCode":null,"errorMessage":"GitHub release ${expectedTag} is a prerelease; only canary updates install prerelease assets","messagePattern":"GitHub release (.+?) is a prerelease; only canary updates install prerelease assets","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/coding-agent/src/cli/update-cli.ts","lineNumber":206,"sourceCode":" * still pins the download to the specific requested version.\n */\nexport function resolveReleaseBinaryAsset(\n\trelease: unknown,\n\texpectedTag: string,\n\tbinaryName: string,\n\toptions: { allowPrerelease?: boolean } = {},\n): ReleaseBinaryAsset {\n\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\") {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/update-cli.ts#L188-L224","documentation":"By default the updater only installs published stable releases. resolveReleaseBinaryAsset rejects a release whose prerelease flag is true unless options.allowPrerelease is set — the canary channel passes that flag since canary GitHub releases are published as prereleases. The exact-tag match still pins the download even for prereleases.","triggerScenarios":"Running a stable `omp update` while the resolved latest release is marked prerelease on GitHub; using a channel configuration that resolves to a prerelease tag without enabling allowPrerelease; testing a canary tag through the stable update path.","commonSituations":"A hotfix shipped first as a prerelease and the stable updater picks it up; users manually requesting a canary version through the stable channel; release marked prerelease after a re-publish.","solutions":["Wait for the stable (non-prerelease) release and retry the update.","Switch to the canary update channel, which sets allowPrerelease and installs prerelease assets for its exact tags.","If you intended a specific prerelease tag, use the channel path that supports prereleases rather than the stable updater.","Check the releases page to confirm the release's prerelease status."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if (release.prerelease === true && !allowPrerelease) {\n  throw new Error(`${release.tag_name} is a prerelease; use the canary channel to install it`);\n}","typeGuard":"function isStableOrAllowed(v: { prerelease: boolean }, allowPrerelease: boolean): boolean {\n  return v.prerelease === false || allowPrerelease;\n}","tryCatchPattern":"try {\n  const asset = resolveReleaseBinaryAsset(release, expectedTag, binaryName, { allowPrerelease });\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"is a prerelease\")) {\n    console.error(\"Stable updater hit a prerelease; switch to canary or wait for stable.\");\n  }\n  throw err;\n}","preventionTips":["Match the update channel to the release kind: canary channel for prereleases, stable otherwise.","Wait for the stable cut instead of chasing freshly marked prereleases.","In CI, pin stable tags and avoid latest-prerelease lookups.","Pass allowPrerelease only in canary-specific code paths."],"tags":["github","update","prerelease","channel"],"backgroundTag":"prerelease-not-allowed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}