{"record":{"id":"96a1e0f04869455b","repo":"NousResearch/hermes-agent","slug":"image-too-large-max-mb-mb","errorCode":null,"errorMessage":"image too large (max ${mb} MB)","messagePattern":"image too large \\(max (.+?) MB\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"web/src/lib/chatImagePaste.ts","lineNumber":129,"sourceCode":"\n/**\n * Upload a browser clipboard/drop image to ``HERMES_HOME/images`` via the\n * dedicated chat upload endpoint and return the absolute gateway path.\n *\n * The dashboard Chat tab is an xterm mirror of a TUI running INSIDE the\n * gateway. The container has no access to the browser's clipboard, so the\n * server-side ``clipboard.paste`` path can never see a pasted image.\n * Upload the bytes the browser already holds, then hand the path to the\n * TUI's ``/image`` command.\n */\nexport async function uploadChatImage(\n  blob: Blob,\n  profile = \"\",\n): Promise<ChatImageUploadResult> {\n  if (blob.size === 0) throw new Error(\"clipboard image is empty\");\n  if (blob.size > MAX_IMAGE_BYTES) {\n    const mb = Math.round(MAX_IMAGE_BYTES / (1024 * 1024));\n    throw new Error(`image too large (max ${mb} MB)`);\n  }\n\n  const mime = blob.type || \"image/png\";\n  const ext = IMAGE_MIME_EXT[mime] || \"png\";\n  const filename =\n    blob instanceof File && blob.name\n      ? blob.name\n      : `clipboard.${ext}`;\n  const file =\n    blob instanceof File\n      ? blob\n      : new File([blob], filename, { type: mime });\n\n  const dataUrl = await fileToDataUrl(file);\n  const qs = profile ? `?profile=${encodeURIComponent(profile)}` : \"\";\n  const res = await authedFetch(`/api/chat/image-upload${qs}`, {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/web/src/lib/chatImagePaste.ts#L111-L147","documentation":"uploadChatImage enforces a client-side size ceiling (MAX_IMAGE_BYTES) on pasted images before converting them to a data URL. The error message includes the computed MB limit. It prevents oversized payloads from being base64-embedded into a JSON POST to /api/chat/image-upload.","triggerScenarios":"Pasting a screenshot or photo whose blob.size exceeds MAX_IMAGE_BYTES; common with full-screen 4K/retina screenshots or high-bit-depth PNGs.","commonSituations":"Multi-monitor retina screenshots, pasted lossless screenshots from pro tools, or scanned documents. Users on slow links also hit gateway body-size limits around the same threshold.","solutions":["Crop or downscale the image before pasting (e.g. take a region screenshot instead of full screen).","Re-encode to JPEG to shrink the payload, or attach the file directly if the UI supports file attach.","If you own the deployment and genuinely need larger images, raise the limit at both the client constant and any server body-size cap."],"exampleFix":"// before\nawait uploadChatImage(originalPngBlob)\n\n// after\nconst smaller = await compressToJpeg(originalPngBlob, 0.8)\nawait uploadChatImage(smaller)","handlingStrategy":"validation","validationCode":"import { MAX_IMAGE_BYTES } from './chatImagePaste'\n\nif (blob.size > MAX_IMAGE_BYTES) {\n  blob = await downscaleUntilUnder(blob, MAX_IMAGE_BYTES) // canvas resize / JPEG re-encode\n}","typeGuard":"const fitsUploadLimit = (b: Blob) => b.size > 0 && b.size <= MAX_IMAGE_BYTES","tryCatchPattern":"try {\n  await uploadChatImage(blob)\n} catch (err) {\n  if (/too large/i.test(String(err))) { blob = await shrink(blob); await uploadChatImage(blob); return }\n  throw err\n}","preventionTips":["Prefer region screenshots over full-screen captures on retina displays.","Compress to JPEG before pasting when the payload is near the limit.","Keep any reverse-proxy body limit at or above MAX_IMAGE_BYTES to avoid server-side 413s after client validation passes."],"tags":["upload","image","size-limit","clipboard"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}