{"record":{"id":"2e10f3d2ba23847e","repo":"affaan-m/ECC","slug":"announcement-delivered-pending-receipt-cleanup-re","errorCode":null,"errorMessage":"announcement delivered; pending receipt cleanup requires attention","messagePattern":"announcement delivered; pending receipt cleanup requires attention","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"scripts/discord/release-announce.mjs","lineNumber":177,"sourceCode":"      throw new Error('announcement has a pending receipt; inspect Discord before clearing it');\n    }\n    const claimId = await addReceiptComment(discussion.id, `${marker}\\n\\nDiscord delivery: pending.`);\n    const payload = buildDiscordPayload({ title: discussion.title, body: discussion.body, url: discussion.url, key });\n    delete payload.nonce;\n    delete payload.enforce_nonce;\n    const response = await request(webhookUrl, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify(payload),\n    });\n    if (!response.ok) {\n      await deleteReceiptComment(claimId);\n      throw new Error(`Discord webhook request failed (${response.status})`);\n    }\n    const message = await response.json();\n    await addReceiptComment(discussion.id, `${marker}\\n\\nDiscord delivery: complete (message ${message.id}).`);\n    await deleteReceiptComment(claimId).catch(() => {\n      console.warn('announcement delivered; pending receipt cleanup requires attention');\n    });\n    console.log('announcement delivered by channel webhook');\n    return;\n  }\n  if (!env.DISCORD_BOT_TOKEN || !/^\\d{10,25}$/.test(env.DISCORD_ANNOUNCE_CHANNEL_ID || '')) {\n    throw new Error('Discord announcement credentials are missing or invalid');\n  }\n  const recent = await discord('GET', `/channels/${env.DISCORD_ANNOUNCE_CHANNEL_ID}/messages?limit=100`);\n  const receipt = findDiscordReceipt(recent, key);\n  if (receipt) {\n    await discord('PUT', `/channels/${env.DISCORD_ANNOUNCE_CHANNEL_ID}/pins/${receipt.id}`);\n    console.log('announcement already delivered; pin verified');\n    return;\n  }\n  const message = await discord('POST', `/channels/${env.DISCORD_ANNOUNCE_CHANNEL_ID}/messages`, buildDiscordPayload({\n    title: discussion.title,\n    body: discussion.body,\n    url: discussion.url,","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/discord/release-announce.mjs#L159-L195","documentation":"In release-announce.mjs, after the Discord webhook delivers the announcement and the success receipt comment is added, the script deletes the temporary claim receipt. If that deletion fails, it logs this warning instead of failing — the announcement was delivered, but a pending receipt comment remains on the discussion and needs manual cleanup.","triggerScenarios":"deleteReceiptComment(claimId) rejects (e.g. GitHub API error, permission issue, or the comment was already removed) inside the .catch() after successful webhook delivery; deliver() completes but leaves the claim receipt behind.","commonSituations":"GitHub API transient failure or rate limit right after Discord delivery; token lacking permission to delete issue comments; concurrent runs where another process already consumed/deleted the claim receipt.","solutions":["Manually delete the leftover claim receipt comment (identified by the receipt marker) from the GitHub discussion","Re-run the release-announce script in a dry/check mode if available to verify no other receipts are pending","Check the GitHub token's permissions (needs comment deletion rights) and any API rate-limit events in the run window","If transient, no action beyond cleanup is needed — the announcement itself was delivered"],"exampleFix":"# before (manual cleanup)\n# find comment containing the receipt marker on the discussion and delete it\n# after: hardened cleanup with retry in the script\nawait deleteReceiptComment(claimId).catch(async e => {\n  await new Promise(r => setTimeout(r, 1000));\n  return deleteReceiptComment(claimId);\n}).catch(() => console.warn('announcement delivered; pending receipt cleanup requires attention'));","handlingStrategy":"retry","validationCode":"// before delivery, confirm token can manage comments\nconst probe = await octokit.rest.issues.getComment({ owner, repo, comment_id: claimId });\nif (!probe.data) console.warn('claim receipt missing before delivery');","typeGuard":null,"tryCatchPattern":"await deleteReceiptComment(claimId).catch(err => retryDelete(claimId, 3))\n  .catch(() => console.warn('announcement delivered; pending receipt cleanup requires attention'));","preventionTips":["Use a GitHub token with repo/issues comment write and delete permissions","Add retry-with-backoff around receipt comment deletion","Monitor for the receipt marker after runs and clean up leftovers promptly","Avoid concurrent release-announce runs against the same discussion"],"tags":["github-api","discord","webhook","cleanup","resilience"],"backgroundTag":"http-error-response","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}