{"record":{"id":"7d78990462a46049","repo":"can1357/oh-my-pi","slug":"discord-webhook-credential-must-use-https","errorCode":null,"errorMessage":"Discord webhook credential must use HTTPS","messagePattern":"Discord webhook credential must use HTTPS","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploaders-discord.ts","lineNumber":36,"sourceCode":"\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);\n}\n\nfunction parseMessage(value: unknown): DiscordMessage {\n\tif (!value || typeof value !== \"object\") throw new Error(\"Discord returned an invalid message response\");","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploaders-discord.ts#L18-L54","documentation":"Discord webhook endpoints must be reached over HTTPS; the uploader rejects any credential URL whose protocol is not `https:`. This prevents leaking the webhook token (which allows posting and deleting messages) over plaintext HTTP.","triggerScenarios":"The `webhookUrl` credential parses as a URL but uses http:// (or ftp://, file://, etc.) — e.g. someone wrote `http://discord.com/api/webhooks/<id>/<token>` or a proxy rewrite produced an http scheme.","commonSituations":"Manually downgrading the scheme to work around a proxy; a template or docs snippet showing http; a local reverse-proxy setup where an http:// URL was substituted for the real Discord webhook.","solutions":["Change the credential scheme to https://discord.com/api/webhooks/...","If routing through a proxy, keep the webhook URL https and configure TLS at the proxy instead of rewriting to http","Re-copy the webhook URL from Discord, which is always https"],"exampleFix":"// before\nwebhookUrl = http://discord.com/api/webhooks/1234567890/token-value\n// after\nwebhookUrl = https://discord.com/api/webhooks/1234567890/token-value","handlingStrategy":"validation","validationCode":"const url = new URL(webhookUrl);\nif (url.protocol !== 'https:') {\n  throw new Error(`Discord webhook must use https://, got ${url.protocol}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await publishToDiscord(blob);\n} catch (err) {\n  if (err.message.includes('must use HTTPS')) {\n    logger.error('Rewrite the webhookUrl with https:// scheme');\n  } else {\n    throw err;\n  }\n}","preventionTips":["Never hand-edit the webhook URL scheme","Keep TLS termination at Discord or a trusted https-speaking proxy","Validate protocol at config load time","Treat the webhook token as a secret — http would expose it"],"tags":["discord","webhook","https","security"],"backgroundTag":"insecure-scheme-rejected","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}