{"record":{"id":"5b0ca809dcc3af54","repo":"garrytan/gstack","slug":"image-exceeds-math-round-max-image-bytes-1024","errorCode":null,"errorMessage":"image exceeds ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)}MB cap: ${src} (${Math.round(stat.size / 1024 / 1024)}MB)","messagePattern":"image exceeds (.+?)MB cap: (.+?) \\((.+?)MB\\)","errorType":"validation","errorClass":"StrictModeError","httpStatus":null,"severity":"warning","filePath":"make-pdf/src/diagram-prepass.ts","lineNumber":673,"sourceCode":"    // Bound the read BEFORE reading: a markdown image pointing at a special\n    // file (fifo, device) would hang readFileSync, and a multi-GB file would\n    // exhaust memory before any policy ran.\n    let stat: fs.Stats;\n    try {\n      stat = fs.statSync(filePath);\n    } catch {\n      opts.warn(`image unreadable: ${src}`);\n      return buildMissingImagePlaceholder(src);\n    }\n    if (!stat.isFile()) {\n      const msg = `image is not a regular file: ${src}`;\n      if (opts.strict) throw new StrictModeError(msg);\n      opts.warn(msg);\n      return buildMissingImagePlaceholder(src);\n    }\n    if (stat.size > MAX_IMAGE_BYTES) {\n      const msg = `image exceeds ${Math.round(MAX_IMAGE_BYTES / 1024 / 1024)}MB cap: ${src} (${Math.round(stat.size / 1024 / 1024)}MB)`;\n      if (opts.strict) throw new StrictModeError(msg);\n      opts.warn(msg);\n      return buildMissingImagePlaceholder(src);\n    }\n\n    let buf = fs.readFileSync(filePath);\n    let dims = imageDims(buf);\n    let mime = dims?.mime ?? mimeFromExtension(filePath);\n\n    // Print-resolution normalization (D4): rasters only — SVG scales free.\n    if (dims && mime !== \"image/svg+xml\" && dims.width > maxPx) {\n      const tab = opts.getTab();\n      if (tab) {\n        try {\n          const dataUri = `data:${mime};base64,${buf.toString(\"base64\")}`;\n          const scaled = tab.call(\"__downscaleRaster\", dataUri, targetPx, mime);\n          const scaledB64 = scaled.replace(/^data:[^,]*,/, \"\");\n          opts.warn(\n            `downscaled ${path.basename(filePath)} ${dims.width}px → ${targetPx}px ` +","sourceCodeStart":655,"sourceCodeEnd":691,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/make-pdf/src/diagram-prepass.ts#L655-L691","documentation":"StrictModeError thrown when a local image file is a regular file but its byte size exceeds MAX_IMAGE_BYTES. The cap bounds memory before any readFileSync, preventing a multi-GB image from exhausting memory. Non-strict mode warns and substitutes a placeholder; strict makes it fatal. The message shows both the cap (MB) and the actual size (MB).","triggerScenarios":"inlineLocalImages() under --strict where fs.statSync(filePath).size > MAX_IMAGE_BYTES. Typical with a raw camera TIFF, an uncompressed scan, or a mistakenly-referenced video file with an image extension.","commonSituations":"A designer committed a 200MB PSD exported as PNG; a doc references a print-resolution 300DPI A0 poster; an asset混淆 with a .png-named data dump; a CI machine with limited RAM hitting OOM before this guard existed.","solutions":["Downscale/compress the image below MAX_IMAGE_BYTES (e.g. `convert big.png -resize 50% big.png`).","Reference a smaller, web-resolution variant of the image.","Drop --strict to degrade to a warn + placeholder.","If the large image is intentional and print resolution matters, raise MAX_IMAGE_BYTES in a fork after verifying available memory."],"exampleFix":"# before\n$ make-pdf --strict report.md  # image is 180MB\nError: image exceeds 64MB cap: ./assets/poster.png (180MB)\n\n# after: downscale\n$ convert ./assets/poster.png -resize 25% ./assets/poster.png\n$ make-pdf --strict report.md","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nimport path from 'node:path';\n\nconst MAX_IMAGE_BYTES = 64 * 1024 * 1024; // match the library constant\nfunction findOversizedImages(markdown: string, inputDir: string): { src: string; size: number }[] {\n  const re = /!\\[[^\\]]*\\]\\((?!https?:|data:)([^)]+)\\)/g;\n  const big: { src: string; size: number }[] = [];\n  let m: RegExpExecArray | null;\n  while ((m = re.exec(markdown))) {\n    const p = path.resolve(inputDir, decodeURIComponent(m[1]));\n    try { const s = fs.statSync(p); if (s.isFile() && s.size > MAX_IMAGE_BYTES) big.push({ src: m[1], size: s.size }); } catch {}\n  }\n  return big;\n}","typeGuard":"import { StrictModeError } from './diagram-prepass';\nfunction isStrictModeError(e: unknown): e is StrictModeError {\n  return e instanceof StrictModeError;\n}","tryCatchPattern":null,"preventionTips":["Compress assets before committing (`pngquant`, `cjpeg`, `convert -resize`).","Reference web-resolution variants, not print masters, in markdown.","Add a pre-commit size check on the assets folder.","Raise MAX_IMAGE_BYTES in a fork only after confirming available memory."],"tags":["make-pdf","image","memory","strict-mode","size-limit"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}