can1357/oh-my-pi · error · ImageInputTooLargeError

Image file too large: ${formatBytes(stat.size)} exceeds ${fo

Error message

Image file too large: ${formatBytes(stat.size)} exceeds ${formatBytes(maxBytes)} limit.

What it means

loadImageInput stats the resolved file before reading and throws ImageInputTooLargeError if its size exceeds the effective maxBytes (options.maxBytes ?? MAX_IMAGE_INPUT_BYTES), preventing oversized images from being base64-encoded and sent to the provider.

Source

Thrown at packages/coding-agent/src/utils/image-loading.ts:461

/** Normalizes historical image blocks in an ephemeral provider request. */
export async function normalizeProviderContextImagesForModel(context: Context, model: Model): Promise<Context> {
	const messages = await normalizeModelContextMessages(context.messages, model);
	return messages === context.messages ? context : { ...context, messages };
}

export async function loadImageInput(options: LoadImageInputOptions): Promise<LoadedImageInput | null> {
	const maxBytes = options.maxBytes ?? MAX_IMAGE_INPUT_BYTES;
	const resolvedPath = options.resolvedPath ?? resolveReadPath(options.path, options.cwd);
	const metadata = options.detectedMimeType
		? { mimeType: options.detectedMimeType }
		: await readImageMetadata(resolvedPath);
	const mimeType = metadata?.mimeType;
	if (!mimeType) return null;

	const stat = await Bun.file(resolvedPath).stat();
	if (stat.size > maxBytes) {
		throw new ImageInputTooLargeError(stat.size, maxBytes);
	}

	const inputBuffer = await fs.readFile(resolvedPath);
	return loadInMemoryImageInput({
		image: { type: "image", data: inputBuffer.toBase64(), mimeType },
		resolvedPath,
		textNotePrefix: "Read image file",
		autoResize: options.autoResize,
		maxBytes,
		excludeWebP: options.excludeWebP,
	});
}

/** Rasterizes an explicitly selected local SVG/SVGZ into a vision-model image input. */
export async function loadSvgImageInput(options: LoadImageInputOptions): Promise<LoadedImageInput | null> {
	const resolvedPath = options.resolvedPath ?? resolveReadPath(options.path, options.cwd);
	const extension = path.extname(resolvedPath).toLowerCase();
	if (extension !== ".svg" && extension !== ".svgz") return null;

View on GitHub (pinned to 9690622007)

Solutions

  1. Downscale or recompress the image file before loading (JPEG conversion, smaller dimensions).
  2. Increase the maxBytes option at the call site.
  3. Strip metadata (EXIF) to shrink the file.
  4. Pre-check with fs.stat and inform the user the file exceeds the limit before calling load.

Example fix

// before: await loadImageInput("/tmp/screenshot.png"); // default limit  // after: downscale/re-encode (e.g. magick screenshot.png -resize 1568x1568> -quality 80 screenshot.jpg), then await loadImageInput("/tmp/screenshot.jpg");
Defensive patterns

Strategy: validation

Validate before calling

const stat = await fs.stat(resolvedPath); if (stat.size > maxBytes) throw new Error(`refusing to load ${resolvedPath}: ${stat.size} > ${maxBytes} bytes`);

Try / catch

try { const img = await loadImageInput(resolvedPath, { maxBytes }); } catch (err) { if (err instanceof ImageInputTooLargeError) { await compressImage(resolvedPath); return loadImageInput(resolvedPath, { maxBytes }); } throw err; }

Prevention

When it happens

Trigger: Calling loadImageInput(path, options) where stat.size of the file at resolvedPath is greater than maxBytes.

Common situations: User attaches a multi-megabyte screenshot or photo; caller passes a small maxBytes; large PNG exports from design tools; photos straight from a camera.

Related errors


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