can1357/oh-my-pi · error
Discord webhook credential does not contain a webhook ID and
Error message
Discord webhook credential does not contain a webhook ID and token
What it means
After URL parsing and the HTTPS check, the uploader extracts the webhook ID and token from the path segment after `webhooks` and validates that the ID is numeric. If the path does not contain `/webhooks/<numeric-id>/<token>`, the credential is not a usable Discord webhook and this error is thrown.
Source
Thrown at packages/coding-agent/src/blob-broker/uploaders-discord.ts:43
}
function parseWebhook(value: string): DiscordWebhook {
let url: URL;
try {
url = new URL(value);
} catch {
throw new Error("Discord webhook credential is not a valid URL");
}
if (url.protocol !== "https:") {
throw new Error("Discord webhook credential must use HTTPS");
}
const segments = url.pathname.split("/").filter(Boolean);
const webhooksIndex = segments.indexOf("webhooks");
const id = webhooksIndex >= 0 ? segments[webhooksIndex + 1] : undefined;
const token = webhooksIndex >= 0 ? segments[webhooksIndex + 2] : undefined;
if (!id || !token || !/^\d+$/.test(id)) {
throw new Error("Discord webhook credential does not contain a webhook ID and token");
}
return { id, token };
}
function webhookEndpoint(webhook: DiscordWebhook, suffix?: string): URL {
const base = `${DISCORD_API_ORIGIN}/api/v10/webhooks/${encodeURIComponent(webhook.id)}/${encodeURIComponent(webhook.token)}`;
return new URL(suffix ? `${base}/${suffix}` : base);
}
function parseMessage(value: unknown): DiscordMessage {
if (!value || typeof value !== "object") throw new Error("Discord returned an invalid message response");
const message = value as Record<string, unknown>;
if (typeof message.id !== "string") throw new Error("Discord response did not include a message ID");
if (!Array.isArray(message.attachments)) throw new Error("Discord response did not include an attachment");
const first = message.attachments[0];
if (!first || typeof first !== "object") throw new Error("Discord response did not include an attachment");
const attachmentUrl = (first as Record<string, unknown>).url;
if (typeof attachmentUrl !== "string") throw new Error("Discord attachment did not include a URL");View on GitHub (pinned to 9690622007)
Solutions
- Use the full Copy Webhook URL: https://discord.com/api/webhooks/<numeric-id>/<token>
- Verify both the numeric ID and token segments are present after /webhooks/ in the URL
- Ensure you are not pasting a Slack or other-provider webhook URL into the discord destination
- Recreate the webhook in Discord if the URL was truncated or the token was rotated
Example fix
// before (channel URL, not a webhook) webhookUrl = https://discord.com/channels/1234567890/9876543210 // after webhookUrl = https://discord.com/api/webhooks/1234567890/aBcDeFgHiJkLmNoP
Defensive patterns
Strategy: validation
Validate before calling
function extractWebhookIdAndToken(webhookUrl) {
const url = new URL(webhookUrl);
const segs = url.pathname.split('/').filter(Boolean);
const i = segs.indexOf('webhooks');
const id = i >= 0 ? segs[i + 1] : undefined;
const token = i >= 0 ? segs[i + 2] : undefined;
if (!id || !token || !/^\d+$/.test(id)) {
throw new Error('URL is not a Discord webhook (need /webhooks/<numeric-id>/<token>)');
}
return { id, token };
} Type guard
function isDiscordWebhookUrl(value) {
if (typeof value !== 'string') return false;
try {
const url = new URL(value);
const segs = url.pathname.split('/').filter(Boolean);
const i = segs.indexOf('webhooks');
return i >= 0 && /^\d+$/.test(segs[i + 1] ?? '') && segs[i + 2] !== undefined;
} catch {
return false;
}
} Try / catch
try {
await publishToDiscord(blob);
} catch (err) {
if (err.message.includes('webhook ID and token')) {
logger.error('webhookUrl is not a Discord webhook URL — re-copy from Discord Integrations');
} else {
throw err;
}
} Prevention
- Use the exact Copy Webhook URL from Discord, never a channel or API URL
- Don't confuse Slack/other webhooks with Discord's /webhooks/<id>/<token> shape
- Check the URL wasn't truncated by shell quoting or config escaping
- Validate the /webhooks/<numeric-id>/<token> pattern before saving the credential
When it happens
Trigger: The credential is a valid https URL but its path lacks `webhooks` (e.g. a Discord channel or API URL), the ID or token segment is missing, or the ID is non-numeric (e.g. a webhook created via a guild template or an interaction endpoint ` interactions/<id>/... ` URL was pasted instead).
Common situations: Pasting a Discord channel invite or API URL instead of the webhook URL; using an incoming-webhook URL from Slack (which has a different path shape) in the discord destination; truncating the URL so the token is cut off; Discord's newer `?wait=` or extra-path variants pasted partially.
Related errors
- Discord webhook credential is not a valid URL
- Discord webhook credential must use HTTPS
- Discord returned an invalid message response
- Discord response did not include a message ID
- Discord response did not include an attachment
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/9fc056880c40be66.
Report an issue: GitHub.