affaan-m/ECC · error · Error
GitHub receipt configuration is missing
Error message
GitHub receipt configuration is missing
What it means
The release-announce script delivers release announcements to Discord discussions. When a Discord channel webhook is configured (DISCORD_ANNOUNCE_WEBHOOK_URL), the script also posts a receipt comment back on the GitHub discussion, which requires GitHub API access. It throws this error because delivering via webhook without a GITHUB_TOKEN would make receipt comments impossible.
Solutions
- Set GITHUB_TOKEN in the workflow environment (github.token or a PAT with discussions:write)
- Ensure GITHUB_REPOSITORY is set (it is provided automatically in GitHub Actions; export it locally)
- If receipt comments are not wanted, use the bot-token/channel-id delivery mode instead of the webhook mode
Example fix
// before
env: { DISCORD_ANNOUNCE_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK }} }
// after
env: { DISCORD_ANNOUNCE_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK }}, GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} } Defensive patterns
Strategy: validation
Validate before calling
if (process.env.DISCORD_ANNOUNCE_WEBHOOK_URL && !process.env.GITHUB_TOKEN) throw new Error('GITHUB_TOKEN required for webhook receipt comments'); Type guard
const hasToken = (env) => typeof env.GITHUB_TOKEN === 'string' && env.GITHUB_TOKEN.length > 0;
Try / catch
try { await deliver(discussion); } catch (e) { if (/receipt configuration is missing/.test(e.message)) { console.error('Set GITHUB_TOKEN before using webhook delivery'); process.exit(1); } throw e; } Prevention
- Always pass GITHUB_TOKEN alongside DISCORD_ANNOUNCE_WEBHOOK_URL in workflow env
- Smoke-test the workflow in a dry-run repo before enabling in production
- Validate required env vars at job start with a preflight step
When it happens
Trigger: deliver() is called with DISCORD_ANNOUNCE_WEBHOOK_URL set but GITHUB_REPOSITORY unset (announcementKey needs it) or GITHUB_TOKEN unset, while running in webhook mode.
Common situations: CI workflows configured with only a Discord webhook secret but no GitHub token permission; running the script locally without exporting GITHUB_TOKEN; GITHUB_TOKEN removed from workflow env after switching to webhook delivery.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- Discord announcement credentials are missing or invalid
- GitHub configuration is missing
- GitHub repository configuration is missing
- request retry budget exhausted
- announcement delivered; pending receipt cleanup requires…
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/ea2a37dc054e4500.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/discord/release-announce.mjs:150
`mutation($id:ID!){deleteDiscussionComment(input:{id:$id}){clientMutationId}}`,
{ id: commentId },
);
}
async function discord(method, path, body) {
const response = await request(`https://discord.com/api/v10${path}`, {
method,
headers: { Authorization: `Bot ${env.DISCORD_BOT_TOKEN}`, 'Content-Type': 'application/json' },
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),View on GitHub (pinned to 8321021c54)