can1357/oh-my-pi · error · ImageInputTooLargeError
Image file too large: ${formatBytes(source.byteLength)} exce
Error message
Image file too large: ${formatBytes(source.byteLength)} exceeds ${formatBytes(maxBytes)} limit. What it means
After the stat-based size check, loadSvgImageInput re-checks the bytes actually read from disk and throws ImageInputTooLargeError if the buffer exceeds maxBytes — defense in depth catching size changes between stat and read (file grew concurrently, or compressed .svgz content differs).
Source
Thrown at packages/coding-agent/src/utils/image-loading.ts:489
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;
const maxBytes = options.maxBytes ?? MAX_IMAGE_INPUT_BYTES;
const stat = await Bun.file(resolvedPath).stat();
if (stat.size > maxBytes) {
throw new ImageInputTooLargeError(stat.size, maxBytes);
}
const source = await fs.readFile(resolvedPath);
if (source.byteLength > maxBytes) {
throw new ImageInputTooLargeError(source.byteLength, maxBytes);
}
let png: Uint8Array;
try {
png = await rasterizeSvg(source, SVG_IMAGE_MAX_EDGE_PX, SVG_IMAGE_MAX_EDGE_PX);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
throw new Error(`Could not rasterize SVG: ${message}`);
}
return loadInMemoryImageInput({
image: {
type: "image",
data: Buffer.from(png.buffer, png.byteOffset, png.byteLength).toString("base64"),
mimeType: "image/png",
},
resolvedPath,
textNotePrefix: "Read SVG file",View on GitHub (pinned to 9690622007)
Solutions
- Minify the SVG and retry after the source stops changing.
- Ensure the SVG file is fully written (await the download/build step) before loading.
- Raise maxBytes if legitimately large SVGs are expected.
- Load from a stable copy (write to a temp file and load that) rather than a live output path.
Example fix
// before: await loadImageInput(buildDir + "/icon.svgz"); // may still be growing // after: await buildComplete; then await loadImageInput(buildDir + "/icon.svgz");
Defensive patterns
Strategy: validation
Validate before calling
const bytes = await Bun.file(svgPath).bytes(); if (bytes.byteLength > maxBytes) throw new Error(`SVG bytes ${bytes.byteLength} exceed ${maxBytes}`); Try / catch
try { const img = await loadImageInput(svgPath); } catch (err) { if (err instanceof ImageInputTooLargeError) { await Bun.write(stableCopy, await Bun.file(svgPath).arrayBuffer()); return loadImageInput(stableCopy); } throw err; } Prevention
- Load SVGs only after their producer (build/download) has finished — avoid TOCTOU.
- Copy to a stable temp path before loading files that may be rewritten concurrently.
- Account for .svgz decompressed size, not just on-disk size.
- Re-check size after any transformation pipeline before loading.
When it happens
Trigger: Calling the SVG loading path when fs.readFile returns more bytes than maxBytes even though the earlier stat passed — file mutated between stat and read, or size reported inconsistently for compressed svgz content.
Common situations: TOCTOU on a file being written concurrently (build output, download still in progress); .svgz files whose content balloons past the limit.
Related errors
- OAuth refresh ownership was lost before persistence
- OAuth credential no longer exists for provider: ${provider}
- No credential with id=${id}
- session header changed during stats cleanup: ${session.path}
- Debugger reported no threads.
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/1bc9e5cd8d1338c4.
Report an issue: GitHub.