affaan-m/ECC · error · Error

${label} is too large (maximum ${maxBytes} bytes).

Error message

${label} is too large (maximum ${maxBytes} bytes).

What it means

Even when the file was small enough at open time, readRegularTextFile streams in 64KB chunks and re-asserts the cap after reading. If the file grew between the fstat size check and the read loop so that total bytes read exceeds maxBytes, the read is aborted. This catches an attacker (or a concurrent appender) who grows the file mid-read to bypass the static size check.

Source

Thrown at scripts/lib/memory-vault.js:183

    }
    if (options.trustedRoot) {
      assertWithinTrustedRoot(filePath, options.trustedRoot, `read ${label}`);
    }
    if (opened.size > BigInt(maxBytes)) {
      throw new Error(`${label} is too large (${opened.size} bytes).`);
    }

    const chunks = [];
    let total = 0;
    while (total <= maxBytes) {
      const buffer = Buffer.alloc(Math.min(64 * 1024, maxBytes + 1 - total));
      const bytesRead = fs.readSync(descriptor, buffer, 0, buffer.length, null);
      if (bytesRead === 0) break;
      chunks.push(buffer.subarray(0, bytesRead));
      total += bytesRead;
    }
    if (total > maxBytes) {
      throw new Error(`${label} is too large (maximum ${maxBytes} bytes).`);
    }
    return decodeUtf8(Buffer.concat(chunks, total), label);
  } finally {
    fs.closeSync(descriptor);
  }
}

function writeCreateOnlyTextFile(filePath, content, trustedRoot) {
  assertWithinTrustedRoot(filePath, trustedRoot, 'write memory');
  const temporaryPath = path.join(
    path.dirname(filePath),
    `.ecc-memory-${process.pid}-${crypto.randomUUID()}.tmp`
  );
  const flags = fs.constants.O_WRONLY
    | fs.constants.O_CREAT
    | fs.constants.O_EXCL
    | (fs.constants.O_NOFOLLOW || 0);
  let descriptor;

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Ensure memory files are written atomically (writeCreateOnly already does) and never appended to in place — find and stop whatever is appending.
  2. Re-run the read after the concurrent writer has finished; the file will then be stable.
  3. Quarantine the growing file (move it out of the vault) and re-save it as a fixed memory via saveMemory.
  4. If the growth is legitimate, split the document so each file is bounded and immutable.

Example fix

// before: another process appends to mem_x.md mid-scan, read aborts
// stop the appender, then re-save as an immutable memory
fs.renameSync(growingPath, growingPath + '.bak');
saveMemory({ title: '...fixed body...', body: fixedBody });
// after: vault contains only immutable, size-bounded files
Defensive patterns

Strategy: retry

Try / catch

async function readStableSize(filePath, options, retries = 2) {
  for (let i = 0; i <= retries; i++) {
    try { return readRegularTextFile(filePath, options); }
    catch (error) {
      if (/too large \(maximum/i.test(error.message) && i < retries) continue;
      throw error;
    }
  }
}

Prevention

When it happens

Trigger: A file whose size at fstat was <= maxBytes but which was appended to during the read loop, pushing total bytes read past maxBytes. Caused by a concurrent writer appending to a memory file, a logging-style memory that is being actively written, or a deliberately growing file under attack.

Common situations: An external process appending to a .md file in the vault mid-scan; a memory document being rewritten by another agent while this reader has it open; a misconfigured tool treating a vault file as a log; filesystem behavior where the file was open in append mode elsewhere.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/bd5663712216302d. Report an issue: GitHub.