{"record":{"id":"1bc9e5cd8d1338c4","repo":"can1357/oh-my-pi","slug":"image-file-too-large-formatbytes-source-bytelen","errorCode":null,"errorMessage":"Image file too large: ${formatBytes(source.byteLength)} exceeds ${formatBytes(maxBytes)} limit.","messagePattern":"Image file too large: (.+?) exceeds (.+?) limit\\.","errorType":"validation","errorClass":"ImageInputTooLargeError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/utils/image-loading.ts","lineNumber":489,"sourceCode":"\t\texcludeWebP: options.excludeWebP,\n\t});\n}\n\n/** Rasterizes an explicitly selected local SVG/SVGZ into a vision-model image input. */\nexport async function loadSvgImageInput(options: LoadImageInputOptions): Promise<LoadedImageInput | null> {\n\tconst resolvedPath = options.resolvedPath ?? resolveReadPath(options.path, options.cwd);\n\tconst extension = path.extname(resolvedPath).toLowerCase();\n\tif (extension !== \".svg\" && extension !== \".svgz\") return null;\n\n\tconst maxBytes = options.maxBytes ?? MAX_IMAGE_INPUT_BYTES;\n\tconst stat = await Bun.file(resolvedPath).stat();\n\tif (stat.size > maxBytes) {\n\t\tthrow new ImageInputTooLargeError(stat.size, maxBytes);\n\t}\n\n\tconst source = await fs.readFile(resolvedPath);\n\tif (source.byteLength > maxBytes) {\n\t\tthrow new ImageInputTooLargeError(source.byteLength, maxBytes);\n\t}\n\n\tlet png: Uint8Array;\n\ttry {\n\t\tpng = await rasterizeSvg(source, SVG_IMAGE_MAX_EDGE_PX, SVG_IMAGE_MAX_EDGE_PX);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Could not rasterize SVG: ${message}`);\n\t}\n\n\treturn loadInMemoryImageInput({\n\t\timage: {\n\t\t\ttype: \"image\",\n\t\t\tdata: Buffer.from(png.buffer, png.byteOffset, png.byteLength).toString(\"base64\"),\n\t\t\tmimeType: \"image/png\",\n\t\t},\n\t\tresolvedPath,\n\t\ttextNotePrefix: \"Read SVG file\",","sourceCodeStart":471,"sourceCodeEnd":507,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/utils/image-loading.ts#L471-L507","documentation":"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).","triggerScenarios":"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.","commonSituations":"TOCTOU on a file being written concurrently (build output, download still in progress); .svgz files whose content balloons past the limit.","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."],"exampleFix":"// before: await loadImageInput(buildDir + \"/icon.svgz\"); // may still be growing  // after: await buildComplete; then await loadImageInput(buildDir + \"/icon.svgz\");","handlingStrategy":"validation","validationCode":"const bytes = await Bun.file(svgPath).bytes(); if (bytes.byteLength > maxBytes) throw new Error(`SVG bytes ${bytes.byteLength} exceed ${maxBytes}`);","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["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."],"tags":["svg","file-size","race-condition"],"backgroundTag":"file-too-large","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}