{"record":{"id":"79425a80393c19ef","repo":"moeru-ai/airi","slug":"screenshot-must-be-a-file-smaller-than-8-mib","errorCode":null,"errorMessage":"Screenshot must be a file smaller than 8 MiB.","messagePattern":"Screenshot must be a file smaller than 8 MiB\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/stage-tamagotchi/src/main/services/airi/computer-use/runtime.ts","lineNumber":146,"sourceCode":"      }\n      catch {\n        // Help output is text. Keep it intact for command discovery.\n      }\n      return { argv, exitCode, output, stderr }\n    })\n  }\n\n  async function readImage(input: unknown): Promise<string> {\n    const { path } = v.parse(v.object({ path: v.string() }), input)\n    return enqueue(async () => {\n      const root = await realpath(options.storeRoot)\n      const target = await realpath(path)\n      const within = relative(root, target)\n      if (!within || isAbsolute(within) || within === '..' || within.startsWith(`..${sep}`))\n        throw new Error('Only screenshots from this AIRI computer-use store can be read.')\n      const info = await stat(target)\n      if (!info.isFile() || info.size > 8 * 1024 * 1024)\n        throw new Error('Screenshot must be a file smaller than 8 MiB.')\n      const data = await readFile(target)\n      const png = data.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n      const jpeg = data[0] === 255 && data[1] === 216 && data[2] === 255\n      if (!png && !jpeg)\n        throw new Error('Screenshot must be PNG or JPEG.')\n      return `data:image/${png ? 'png' : 'jpeg'};base64,${data.toString('base64')}`\n    })\n  }\n\n  /** Rejects queued calls, aborts active work, and waits for the owned daemon to exit. */\n  async function dispose() {\n    disposed = true\n    abort.abort()\n    await queue\n    try {\n      await daemon?.stop()\n    }\n    finally {","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/moeru-ai/airi/blob/438a067dde47aa0bdb46c2323d1fe293dc805218/apps/stage-tamagotchi/src/main/services/airi/computer-use/runtime.ts#L128-L164","documentation":"readImage() enforces a hard 8 MiB size limit (stat().size) and requires the target to be a regular file before base64-encoding it into a data URL. Oversized files are rejected to keep the in-memory base64 payload and the model context bounded.","triggerScenarios":"stat() reports a file larger than 8 * 1024 * 1024 bytes, or the path resolves to a directory/FIFO rather than a regular file.","commonSituations":"High-resolution multi-monitor captures saved as uncompressed PNG; reading a raw/bitmap dump instead of the CLI's encoded screenshot; pointing at a directory inside the store.","solutions":["Re-capture with a smaller region or use JPEG output to reduce size","Check file size with fs.stat before calling readImage and downscale/compress if > 8 MiB","Ensure the path is the actual screenshot file, not a directory"],"exampleFix":"// before\nif ((await stat(p)).size > 8 * 1024 * 1024) { /* will throw */ }\nawait readImage({ path: p })\n// after\nconst info = await stat(p)\nif (info.size > 8 * 1024 * 1024) p = await reencodeAsJpeg(p)\nawait readImage({ path: p })","handlingStrategy":"validation","validationCode":"import { stat } from 'node:fs/promises'\nasync function isReadableScreenshotSize(p: string): Promise<boolean> {\n  const info = await stat(p)\n  return info.isFile() && info.size <= 8 * 1024 * 1024\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await readImage({ path })\n} catch (e) {\n  if (e instanceof Error && e.message.includes('smaller than 8 MiB')) {\n    const shrunk = await compressImage(path)\n    return readImage({ path: shrunk })\n  }\n  throw e\n}","preventionTips":["Check stat().size before calling readImage and compress/downscale when near 8 MiB","Prefer JPEG output for large multi-monitor captures","Ensure the path is a regular file, not a directory"],"tags":["file-size","limit","image"],"backgroundTag":"payload-too-large","analyzedSha":"438a067dde47aa0bdb46c2323d1fe293dc805218","analyzedAt":"2026-09-17T01:14:42.644Z","contentChangedAt":"2026-09-17T01:14:42.644Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}