affaan-m/ECC · error · Error

announcement has a pending receipt; inspect Discord before…

Error message

announcement has a pending receipt; inspect Discord before clearing it

What it means

Before sending to Discord, the script posts a 'pending' receipt claim comment on the GitHub discussion to make delivery idempotent. If an existing receipt is found but is not marked complete, the script refuses to act: a previous run may have sent the message but never finished, so re-running could duplicate the announcement. It throws this error to force human inspection.

Solutions

  1. Check Discord for whether the announcement was actually posted
  2. If posted and correct, edit or delete the pending receipt comment on the GitHub discussion (or update its status to complete), then re-run
  3. If not posted, delete the pending receipt comment and re-run the workflow
Defensive patterns

Strategy: try-catch

Try / catch

try { await deliver(discussion); } catch (e) { if (/pending receipt/.test(e.message)) { console.error('Inspect the GitHub discussion receipt comment and Discord channel manually, then clear the pending receipt'); process.exit(2); } throw e; }

Prevention

When it happens

Trigger: findReceiptComment(discussion.id, marker) returns a receipt whose discussionReceiptStatus is not 'complete' — i.e. a leftover 'pending' receipt from a crashed or interrupted run.

Common situations: A previous run posted to Discord but crashed before writing the 'complete' receipt; workflow was cancelled mid-delivery; Discord webhook succeeded but the GitHub comment API call failed, leaving the pending claim.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/c7820019b6422ac7. Report an issue: GitHub.

Appendix: source

Thrown at scripts/discord/release-announce.mjs:159

    body: body ? JSON.stringify(body) : undefined,
  });
  if (!response.ok) throw new Error(`Discord request failed (${response.status})`);
  return response.status === 204 ? null : response.json();
}

async function deliver(discussion) {
  const key = announcementKey({ repository: env.GITHUB_REPOSITORY, discussionId: discussion.id });
  if (env.DISCORD_ANNOUNCE_WEBHOOK_URL) {
    if (!env.GITHUB_TOKEN) throw new Error('GitHub receipt configuration is missing');
    const webhookUrl = normalizeDiscordWebhookUrl(env.DISCORD_ANNOUNCE_WEBHOOK_URL);
    const marker = discussionReceiptMarker(key);
    const existingReceipt = await findReceiptComment(discussion.id, marker);
    if (existingReceipt) {
      if (discussionReceiptStatus(existingReceipt) === 'complete') {
        console.log('announcement already delivered');
        return;
      }
      throw new Error('announcement has a pending receipt; inspect Discord before clearing it');
    }
    const claimId = await addReceiptComment(discussion.id, `${marker}\n\nDiscord delivery: pending.`);
    const payload = buildDiscordPayload({ title: discussion.title, body: discussion.body, url: discussion.url, key });
    delete payload.nonce;
    delete payload.enforce_nonce;
    const response = await request(webhookUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });
    if (!response.ok) {
      await deleteReceiptComment(claimId);
      throw new Error(`Discord webhook request failed (${response.status})`);
    }
    const message = await response.json();
    await addReceiptComment(discussion.id, `${marker}\n\nDiscord delivery: complete (message ${message.id}).`);
    await deleteReceiptComment(claimId).catch(() => {
      console.warn('announcement delivered; pending receipt cleanup requires attention');

View on GitHub (pinned to 8321021c54)