{"record":{"id":"08d3b02e5afe7e3c","repo":"CherryHQ/cherry-studio","slug":"file-exceeds-the-max-file-size-bytes-byte-limit","errorCode":null,"errorMessage":"File exceeds the ${MAX_FILE_SIZE_BYTES} byte limit (${snapshot.size} bytes): ${displayPath}","messagePattern":"File exceeds the (.+?) byte limit \\((.+?) bytes\\): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/channels/security/localFileResolver.ts","lineNumber":49,"sourceCode":"  let stats: Awaited<ReturnType<typeof lstat>>\n  try {\n    stats = await lstat(target)\n  } catch (error) {\n    if (isErrnoException(error) && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) {\n      throw new Error(`File not found: ${displayPath}`)\n    }\n    throw error\n  }\n  if (!stats.isFile) {\n    throw new Error(`Not a regular file: ${displayPath}`)\n  }\n\n  // The snapshot pins the inode and fixes the read length at open time, so the size\n  // check and the read see the same file even if the path is replaced meanwhile.\n  const snapshot = await openReadableFileSnapshot(target)\n  try {\n    if (snapshot.size > MAX_FILE_SIZE_BYTES) {\n      throw new Error(`File exceeds the ${MAX_FILE_SIZE_BYTES} byte limit (${snapshot.size} bytes): ${displayPath}`)\n    }\n\n    const data = await readStreamToBuffer(snapshot.createReadStream())\n    // Re-check against the actual read size: the file can grow between stat and read.\n    if (data.length > MAX_FILE_SIZE_BYTES) {\n      throw new Error(`File exceeds the ${MAX_FILE_SIZE_BYTES} byte limit (${data.length} bytes): ${displayPath}`)\n    }\n    const filename = path.basename(requestedPath)\n    return {\n      filename,\n      data: data.toString('base64'),\n      media_type: mimeForFilename(filename),\n      size: data.length\n    }\n  } finally {\n    // Swallow close errors so they can't mask an in-flight resolution error.\n    await snapshot.close().catch(() => {})\n  }","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/channels/security/localFileResolver.ts#L31-L67","documentation":"Thrown by readCanonicalLocalFile() as the first of two size checks. The snapshot (from openReadableFileSnapshot) pins the inode and records the file size at open time. If that size exceeds MAX_FILE_SIZE_BYTES (100 MB = 104857600 bytes), the error fires before any data is read. This is the fast-path rejection: it avoids reading the entire file into memory before discovering it is too large.","triggerScenarios":"Called from resolveWorkspaceFile or resolveLocalFile when the target file's size at open time exceeds 100 MB. The snapshot captures the size from the file descriptor's stat, which reflects the inode state at open time.","commonSituations":"An agent tried to attach a large binary file (video, archive, database dump) as a document; a log file grew past 100 MB; the user pointed the agent at a media file that exceeds the attachment limit.","solutions":["Reduce the file size below 100 MB before attaching — compress, truncate, or extract only the relevant portion.","If a larger limit is needed, change MAX_FILE_SIZE_BYTES in @main/utils/downloadAsBase64 — but consider memory and API constraints first.","For large text files, read only the relevant lines or sections instead of attaching the whole file."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { stat } from '@main/utils/file'\nimport { MAX_FILE_SIZE_BYTES } from '@main/utils/downloadAsBase64'\n\n// Pre-check file size before resolving\nconst s = await stat(AbsoluteFilePathSchema.parse(canonicalPath))\nif (s.size > MAX_FILE_SIZE_BYTES) {\n  throw new Error(`File is ${s.size} bytes — exceeds the ${MAX_FILE_SIZE_BYTES} byte limit`)  \n}","typeGuard":null,"tryCatchPattern":"try {\n  return await readCanonicalLocalFile(requestedPath, canonicalPath, displayPath)\n} catch (error) {\n  if (error instanceof Error && error.message.includes('byte limit')) {\n    logger.warn('File too large to attach', { displayPath })\n    return null\n  }\n  throw error\n}","preventionTips":["Check file size with stat() before attempting to read large files.","Set user expectations: document the 100 MB attachment limit in agent guidelines.","For large text files, implement a line-range read instead of full-file attachment."],"tags":["filesystem","file-size","validation","limit","channels"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}