{"record":{"id":"f5aaff115d83bed5","repo":"can1357/oh-my-pi","slug":"discord-webhook-credential-is-not-a-valid-url","errorCode":null,"errorMessage":"Discord webhook credential is not a valid URL","messagePattern":"Discord webhook credential is not a valid URL","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-discord.ts","lineNumber":32,"sourceCode":"const DISCORD_API_ORIGIN = \"https://discord.com\";\nconst FALLBACK_LIFETIME_MS = 24 * 60 * 60 * 1_000;\n\ninterface DiscordWebhook {\n\tid: string;\n\ttoken: string;\n}\n\ninterface DiscordMessage {\n\tid: string;\n\tattachmentUrl: string;\n}\n\nfunction parseWebhook(value: string): DiscordWebhook {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new Error(\"Discord webhook credential is not a valid URL\");\n\t}\n\n\tif (url.protocol !== \"https:\") {\n\t\tthrow new Error(\"Discord webhook credential must use HTTPS\");\n\t}\n\tconst segments = url.pathname.split(\"/\").filter(Boolean);\n\tconst webhooksIndex = segments.indexOf(\"webhooks\");\n\tconst id = webhooksIndex >= 0 ? segments[webhooksIndex + 1] : undefined;\n\tconst token = webhooksIndex >= 0 ? segments[webhooksIndex + 2] : undefined;\n\tif (!id || !token || !/^\\d+$/.test(id)) {\n\t\tthrow new Error(\"Discord webhook credential does not contain a webhook ID and token\");\n\t}\n\treturn { id, token };\n}\n\nfunction webhookEndpoint(webhook: DiscordWebhook, suffix?: string): URL {\n\tconst base = `${DISCORD_API_ORIGIN}/api/v10/webhooks/${encodeURIComponent(webhook.id)}/${encodeURIComponent(webhook.token)}`;\n\treturn new URL(suffix ? `${base}/${suffix}` : base);","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-discord.ts#L14-L50","documentation":"The Discord uploader parses the configured `webhookUrl` credential with the URL constructor before using it. If the credential string cannot be parsed as a URL at all (new URL throws), this error is thrown so the misconfiguration is reported at destination setup time rather than as a confusing fetch failure.","triggerScenarios":"The `webhookUrl` option in the discord destination config is empty, contains only whitespace, is missing its scheme (e.g. `discord.com/api/webhooks/...`), or contains characters that make it unparseable by `new URL()` (unencoded spaces, stray quotes from copy-paste).","commonSituations":"Copy-pasting a webhook URL with trailing whitespace or quotes; storing the webhook in an env var that was never set so an empty string is passed; hand-typing the URL and omitting `https://`; shell quoting mangling the value in a config file.","solutions":["Copy the webhook URL directly from Discord (Server Settings → Integrations → Webhooks → Copy Webhook URL) including the https:// prefix","Trim whitespace and remove surrounding quotes from the credential value","Confirm the config source (env var, settings file) actually resolves to a non-empty string","Validate the URL with `new URL(value)` locally before saving it to config"],"exampleFix":"// before\nwebhookUrl = discord.com/api/webhooks/123/abc \"\n// after\nwebhookUrl = https://discord.com/api/webhooks/123/abc","handlingStrategy":"validation","validationCode":"function validateWebhookUrl(value) {\n  let url;\n  try {\n    url = new URL(value.trim());\n  } catch {\n    throw new Error('webhookUrl is not a valid URL');\n  }\n  return url;\n}\nvalidateWebhookUrl(process.env.DISCORD_WEBHOOK_URL);","typeGuard":null,"tryCatchPattern":"try {\n  await publishToDiscord(blob);\n} catch (err) {\n  if (err.message.includes('not a valid URL')) {\n    logger.error('DISCORD_WEBHOOK_URL is malformed — copy the full https:// URL from Discord');\n  } else {\n    throw err;\n  }\n}","preventionTips":["Always copy the webhook URL directly from Discord's integration UI","Trim and unquote the value stored in env vars/config files","Validate the credential with new URL() at config load time","Fail fast at startup, not at first upload"],"tags":["discord","webhook","config","url-parsing"],"backgroundTag":"invalid-url-credential","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}