{"record":{"id":"bbdee1ca62357a0f","repo":"can1357/oh-my-pi","slug":"github-release-asset-binaryname-has-an-invalid","errorCode":null,"errorMessage":"GitHub release asset ${binaryName} has an invalid size","messagePattern":"GitHub release asset (.+?) has an invalid size","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/update-cli.ts","lineNumber":222,"sourceCode":"\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}`;\n\tif (asset.browser_download_url !== expectedUrl) {\n\t\tthrow new Error(`GitHub release asset ${binaryName} has an unexpected download URL`);\n\t}\n\n\treturn {\n\t\turl: expectedUrl,\n\t\tsize: asset.size,\n\t\tdigest: `sha256:${digest.toLowerCase()}`,","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/update-cli.ts#L204-L240","documentation":"The updater uses the asset's declared `size` for integrity checking of the downloaded binary. The size field must be a positive safe integer; anything else (missing, non-number, zero, negative, or exceeding Number.MAX_SAFE_INTEGER) means the metadata is unreliable and the download cannot be size-verified.","triggerScenarios":"resolveReleaseBinaryAsset throws when the matched asset fails `typeof asset.size !== \"number\" || !Number.isSafeInteger(asset.size) || asset.size <= 0`.","commonSituations":"A mocked release payload in tests missing the size field, a proxy rewriting the JSON, an API schema change, or (theoretically) an asset larger than Number.MAX_SAFE_INTEGER which cannot occur in practice.","solutions":["Refetch release metadata and retry; if it persists, inspect the raw API response for the asset's size field.","Check whether a proxy/mirror is mangling the JSON response.","Fix test stubs to include a realistic numeric size.","If GitHub changed the field name or type, update resolveReleaseBinaryAsset."],"exampleFix":"// before (stub asset without size)\n{ name: \"omp-linux-x64\", state: \"uploaded\", digest: \"sha256:...\", browser_download_url: \"...\" }\n// after\n{ name: \"omp-linux-x64\", state: \"uploaded\", size: 52428800, digest: \"sha256:...\", browser_download_url: \"...\" }","handlingStrategy":"type-guard","validationCode":"const asset = release.assets?.find(a => a?.name === binaryName);\nif (typeof asset?.size !== \"number\" || !Number.isSafeInteger(asset.size) || asset.size <= 0) {\n  throw new Error(\"Asset metadata missing valid size; refusing to download\");\n}","typeGuard":"function hasValidSize(asset: unknown): asset is { size: number } {\n  const size = (asset as { size?: unknown })?.size;\n  return typeof size === \"number\" && Number.isSafeInteger(size) && size > 0;\n}","tryCatchPattern":"try {\n  await update();\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"has an invalid size\")) {\n    console.error(\"Release asset metadata is corrupt; refetch and retry.\");\n  } else throw err;\n}","preventionTips":["Validate every field of release metadata you consume — never trust the shape blindly.","Keep API-version headers pinned so schema drift is detected deliberately.","In test stubs, always include realistic size values."],"tags":["github-api","release-assets","update","integrity"],"backgroundTag":"malformed-api-response","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}