can1357/oh-my-pi · error

Unsupported image type from URL: ${imageUrl}

Error message

Unsupported image type from URL: ${imageUrl}

What it means

After a successful download the tool checks the Content-Type header (before any ';') and requires it to start with 'image/'. If the server returns text/html (an error page), application/octet-stream, application/pdf, etc., the tool refuses to forward it as an inline image because providers accept only actual image media types.

Source

Thrown at packages/coding-agent/src/tools/image-gen.ts:401

	if (imageUrl.startsWith("data:")) {
		const normalized = normalizeDataUrl(imageUrl.trim());
		if (!normalized.mimeType) {
			throw new Error("mime_type is required when providing raw base64 data.");
		}
		if (!normalized.data) {
			throw new Error("Image data is empty.");
		}
		return { data: normalized.data, mimeType: normalized.mimeType };
	}

	const response = await fetchImpl(imageUrl, { signal });
	if (!response.ok) {
		const rawText = await response.text();
		throw new Error(`Image download failed (${response.status}): ${rawText}`);
	}
	const contentType = response.headers.get("content-type")?.split(";")[0];
	if (!contentType?.startsWith("image/")) {
		throw new Error(`Unsupported image type from URL: ${imageUrl}`);
	}
	const buffer = await response.bytes();
	return { data: buffer.toBase64(), mimeType: contentType };
}

function collectOpenRouterResponseText(message: OpenRouterMessage | undefined): string | undefined {
	if (!message) return undefined;
	if (typeof message.content === "string") {
		const trimmed = message.content.trim();
		return trimmed.length > 0 ? trimmed : undefined;
	}
	if (Array.isArray(message.content)) {
		const texts = message.content
			.filter(part => part.type === "text")
			.map(part => part.text)
			.filter((text): text is string => Boolean(text));
		const combined = texts.join("\n").trim();
		return combined.length > 0 ? combined : undefined;

View on GitHub (pinned to 9690622007)

Solutions

  1. Point to the direct image URL (ends in .png/.jpg, served with image/* content-type) rather than a viewer/page URL
  2. Set the correct Content-Type when uploading the image to object storage (e.g. image/png)
  3. Convert the asset to a real image and pass it as a file path or data: URL instead
  4. If serving SVG, convert to PNG — SVG is often served as text/xml and rejected

Example fix

// before
const url = "https://drive.google.com/file/d/abc/view"; // HTML page
// after
const url = "https://example.com/raw/abc.png"; // served as image/png
Defensive patterns

Strategy: validation

Validate before calling

async function isImageUrl(url: string, fetchImpl: typeof fetch): Promise<boolean> {
	const res = await fetchImpl(url, { method: "HEAD" });
	return (res.headers.get("content-type") ?? "").startsWith("image/");
}

Try / catch

try {
	await genImage({ imageUrl });
} catch (err) {
	if (err instanceof Error && err.message.startsWith("Unsupported image type from URL:")) {
		// fall back: download, sniff bytes, re-serve as data: URL
	}
	throw err;
}

Prevention

When it happens

Trigger: The fetched URL responds 200 but its content-type is not image/* — e.g. a login/interstitial HTML page, an octet-stream download endpoint, a JSON error with 200 status, or a bare IP host serving a default page.

Common situations: URLs that redirect to HTML viewers instead of raw bytes; object storage without a content-type set on upload; endpoints returning SVG served as text/xml; APIs that require an Accept header to serve image bytes.

Related errors


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