thedotmack/claude-mem · error · Error
Discord API error: ${response.status} - ${errorText}
Error message
Discord API error: ${response.status} - ${errorText} What it means
postToDiscord POSTs an embed payload to the DISCORD_UPDATES_WEBHOOK URL read from .env. If Discord returns a non-2xx (4xx rate-limit/invalid-webhook/auth, 5xx Discord outage), the script reads the response body and throws a combined error. The webhook is fire-and-forget release notification; this error aborts the notification.
Source
Thrown at scripts/discord-release-notify.js:92
},
],
footer: {
text: 'claude-mem • Persistent memory for Claude Code',
},
timestamp: new Date().toISOString(),
},
],
};
const response = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Discord API error: ${response.status} - ${errorText}`);
}
return true;
}
async function main() {
const version = process.argv[2];
const customNotes = process.argv[3];
if (!version) {
console.error('Usage: node scripts/discord-release-notify.js <version> [notes]');
console.error('Example: node scripts/discord-release-notify.js v7.4.2');
process.exit(1);
}
console.log(`📣 Posting release notification for ${version}...`);
const webhookUrl = loadEnv();View on GitHub (pinned to d768ba3643)
Solutions
- Verify the webhook URL in .env (DISCORD_UPDATES_WEBHOOK) is current and not revoked — regenerate in Discord and re-test with curl.
- If the body mentions 'rate limit' (429), wait the indicated retry_after seconds and re-run; this script posts at most once per release so a one-off retry suffices.
- If 400 on embed size, lower the truncate maxLength in cleanNotes/truncate (currently 2000) and ensure fields stay within Discord's limits.
- For 5xx, re-run after a short wait — Discord outages are transient.
Example fix
// before
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Discord API error: ${response.status} - ${errorText}`);
}
// after — handle 429 rate limit with its Retry-After header
if (!response.ok) {
if (response.status === 429) {
const retryAfter = parseFloat(response.headers.get('retry-after') || '1') * 1000;
await new Promise(r => setTimeout(r, retryAfter));
return postToDiscord(webhookUrl, version, notes); // one retry
}
const errorText = await response.text();
throw new Error(`Discord API error: ${response.status} - ${errorText}`);
} Defensive patterns
Strategy: retry
Validate before calling
// Validate the webhook shape and a cheap reachability before posting:
function looksLikeDiscordWebhook(url: string): boolean {
return /^https:\/\/discord(?:app)?\.com\/api\/(?:webhooks|v\d+\/webhooks)\/[0-9]+\/[A-Za-z0-9_-]+$/.test(url);
}
if (!looksLikeDiscordWebhook(webhookUrl)) throw new Error('DISCORD_UPDATES_WEBHOOK is malformed'); Type guard
function isDiscordRateLimit(res: Response): boolean {
return res.status === 429;
} Try / catch
// main() already wraps postToDiscord in try/catch (discord-release-notify.js:117-123). // For 429, honor Retry-After and retry once (see exampleFix). For 4xx auth/not-found, // surface the message and exit non-zero — do not retry a revoked webhook.
Prevention
- Keep DISCORD_UPDATES_WEBHOOK in .env current; rotate via Discord channel settings, then update .env.
- Don't post repeatedly in a short window — Discord rate-limits aggressively.
- Validate the payload against Discord embed limits (description <= 2000 chars, <= 25 fields) before sending.
When it happens
Trigger: Webhook URL revoked or malformed (401/403/404). Rate limited (429) from posting too frequently. Payload exceeds Discord embed limits — title+description over 2000 chars after truncate, or too many fields (400). Discord 5xx outage.
Common situations: Webhook rotated in Discord channel settings and .env not updated. Re-running the script rapidly after a release (429). Notes containing content that pushes the embed over limits. Discord temporarily degraded.
Related errors
- SSE stream returned HTTP ${response.status}
- ${timeoutMessage} (timed out after ${timeoutMs}ms)
- Failed to get processing status: ${res.status}
- Failed to trigger processing: ${res.status}
- Worker request timed out after ${WORKER_FETCH_TIMEOUT_MS}ms:
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/2337353f3cc2102f.
Report an issue: GitHub.