{"record":{"id":"98d81f22eb15df68","repo":"agalwood/Motrix","slug":"plugin-fs-chunk-too-large","errorCode":"plugin.fs.chunk_too_large","errorMessage":"plugin.fs.chunk_too_large: maxChunkSize ${maxChunkSize} > limit ${maxChunk}","messagePattern":"plugin\\.fs\\.chunk_too_large: maxChunkSize (.+?) > limit (.+?)","errorType":"validation","errorClass":"FsTaskError","httpStatus":null,"severity":"error","filePath":"src/core/plugin/capabilities/fs-task.ts","lineNumber":191,"sourceCode":"        state.handle.close().catch(() => {})\n      }\n    }\n\n    const ensureOpen = (): Promise<void> => {\n      if (openPromise !== null) return openPromise\n      openPromise = fs.open(filePath(), 'r').then((h) => {\n        state.handle = h\n      })\n      return openPromise\n    }\n\n    // Start idle timer immediately\n    resetIdle()\n\n    const reader: FsTaskReader = {\n      async read(maxChunkSize: number): Promise<Uint8Array | null> {\n        if (maxChunkSize > maxChunk) {\n          throw new FsTaskError(\n            'plugin.fs.chunk_too_large',\n            `plugin.fs.chunk_too_large: maxChunkSize ${maxChunkSize} > limit ${maxChunk}`\n          )\n        }\n\n        // Auto-closed by idle timer\n        if (state.closed) return null\n\n        // Length cap: refuse to read past the requested length\n        if (maxLength !== Infinity && bytesDelivered >= maxLength) return null\n\n        await ensureOpen()\n        if (state.closed) return null\n\n        const remaining =\n          maxLength === Infinity\n            ? maxChunkSize\n            : Math.min(maxChunkSize, maxLength - bytesDelivered)","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/capabilities/fs-task.ts#L173-L209","documentation":"Thrown by FsTaskReader.read(maxChunkSize) when the requested maxChunkSize exceeds the task's configured `maxReaderChunkBytes` (referenced as `maxChunk`, default is the module's DEFAULT_MAX_CHUNK, exercised as 16 MB in tests). The cap bounds per-read allocation. Code is `plugin.fs.chunk_too_large`. Checked synchronously at the top of read() before any I/O.","triggerScenarios":"Calling `reader.read(32 * 1024 * 1024)` on a task whose maxReaderChunkBytes is 16 MB; passing a user-controlled buffer size into read() without clamping; hardcoding a large chunk size that worked on a differently-configured task.","commonSituations":"Plugin tuned for a different default; passing through an HTTP range size unchanged; copying example code that assumed a higher cap.","solutions":["Clamp maxChunkSize to the task's limit before each read: `Math.min(reqSize, knownLimit)`.","Raise maxReaderChunkBytes in FsTask options if larger reads are needed and memory permits.","Discover the cap from the task config rather than hardcoding a number.","Loop reads with a fixed safe size (e.g. 1 MB) instead of one large request."],"exampleFix":"// before\nconst buf = await reader.read(32 * 1024 * 1024) // > default 16 MB\n\n// after\nconst CHUNK = 4 * 1024 * 1024 // safely under the 16 MB default\nlet buf: Uint8Array | null\nwhile ((buf = await reader.read(CHUNK)) !== null) { /* handle */ }","handlingStrategy":"validation","validationCode":"function clampChunk(reqSize: number, limit: number): number {\n  if (!Number.isFinite(reqSize) || reqSize <= 0) return Math.min(1 << 20, limit)\n  return Math.min(reqSize, limit)\n}","typeGuard":"function isChunkTooLarge(e: unknown): boolean {\n  return e instanceof Error && (e as FsTaskError).code === 'plugin.fs.chunk_too_large'\n}","tryCatchPattern":"try {\n  const buf = await reader.read(reqSize)\n} catch (e) {\n  if (isChunkTooLarge(e)) { /* retry with a smaller, safe chunk size */ }\n  else throw e\n}","preventionTips":["Discover maxReaderChunkBytes from task config rather than guessing.","Use a conservative fixed chunk size (e.g. 1–4 MB) in read loops.","Clamp externally-derived sizes before calling read()."],"tags":["fs","task","memory","limits","read"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}