can1357/oh-my-pi · error

Discord returned an invalid message response

Error message

Discord returned an invalid message response

What it means

After uploading the file via the Discord webhook (with ?wait=true so Discord returns the created message), the uploader validates the response JSON: it must be an object containing a message `id` string and a non-empty `attachments` array. A body that is not an object fails this first check, meaning Discord did not return the expected message resource.

Source

Thrown at packages/coding-agent/src/blob-broker/uploaders-discord.ts:54

		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");
	try {
		const parsed = new URL(attachmentUrl);
		if (parsed.protocol !== "https:") throw new Error();
	} catch {
		throw new Error("Discord attachment URL is invalid");
	}
	return { id: message.id, attachmentUrl };
}

function attachmentExpiry(url: string, now: number): number {
	const signedExpiry = new URL(url).searchParams.get("ex");

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the raw response body and status from the webhook POST to see what Discord actually returned
  2. Ensure no proxy or DNS override (e.g. for censored regions) is injecting HTML challenge pages for discord.com
  3. Retry the upload — transient gateway errors can return non-JSON bodies
  4. Verify webhook validity via GET /api/v10/webhooks/<id>/<token> and that `wait=true` is honored for your webhook type

Example fix

// before (mock returns a bare JSON array)
[{ "id": "1" }]
// after (return the message object Discord sends)
{ "id": "9999", "attachments": [{ "id": 0, "url": "https://cdn.discordapp.com/attachments/.../file.txt" }] }
Defensive patterns

Strategy: try-catch

Type guard

function isDiscordMessage(v) {
  return typeof v === 'object' && v !== null &&
    typeof v.id === 'string' &&
    Array.isArray(v.attachments) && v.attachments.length > 0 &&
    typeof v.attachments[0]?.url === 'string';
}

Try / catch

try {
  const body = await response.json();
  if (!isDiscordMessage(body)) {
    throw new Error(`Discord webhook returned unexpected body: ${JSON.stringify(body).slice(0, 200)}`);
  }
} catch (err) {
  logger.error('Discord webhook upload failed or response malformed', { cause: err });
  // retry once or fall back to another destination
}

Prevention

When it happens

Trigger: POST to /api/v10/webhooks/<id>/<token>?wait=true returned 2xx but the body is not a JSON object — an HTML error/interstitial page from a proxy, a JSON array, `null`, or an empty body being decoded into a non-object value.

Common situations: Corporate proxies or Cloudflare challenge pages intercepting discord.com; a stubbed Discord endpoint in tests returning an incomplete body; Discord API changes; hitting a rate-limit/gateway response that still parsed to a non-object.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/683cf976ba274978. Report an issue: GitHub.