thedotmack/claude-mem · error · Error

projection_error: one operation exceeds projection request…

Error message

projection_error: one operation exceeds projection request byte budget

What it means

getProjectionPage() batches ops subject to a byte budget (maxBytes, capped at PROJECTION_PAGE_MAX_BYTES). If a single serialized operation alone exceeds that budget — before any op has been accumulated — no valid page can be produced, so the DO throws this projectionError instead of returning an oversized request.

Solutions

  1. Raise maxBytes (and confirm it is bytes, not ops) so it comfortably exceeds the largest op in the range; the DO caps it at PROJECTION_PAGE_MAX_BYTES, so if the op exceeds the server cap the cap itself must be raised in config/code.
  2. Increase PROJECTION_PAGE_MAX_OPS/PAGE byte constants in the hub if large ops are legitimate for your workload.
  3. Split overly large client mutations at write time so no single canonical op exceeds the projection byte budget.
  4. Catch this error and route the offending seq to a dead-letter/splitting path instead of retrying the same page forever.

Example fix

// before
const page = hub.getProjectionPage(token, target, userId, 500, 1024);
// after
const page = hub.getProjectionPage(token, target, userId, 500, PROJECTION_PAGE_MAX_BYTES);
Defensive patterns

Strategy: validation

Validate before calling

const byteLimit = Math.min(requestedBytes, PROJECTION_PAGE_MAX_BYTES);
if (largestKnownOpBytes > byteLimit) {
  throw new Error(`op too large for projection budget: ${largestKnownOpBytes} > ${byteLimit}`);
}

Try / catch

try {
  page = hub.getProjectionPage(token, target, userId, maxOps, maxBytes);
} catch (e) {
  if (String(e).includes('byte budget')) {
    // raise maxBytes to server cap or split/skip the oversized op
    page = hub.getProjectionPage(token, target, userId, maxOps, PROJECTION_PAGE_MAX_BYTES);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling getProjectionPage with maxBytes set very low (e.g. 1 or a tiny value) while the log contains an op larger than that budget; or a single canonical op genuinely larger than PROJECTION_PAGE_MAX_BYTES.

Common situations: Operator passes maxBytes as a small number intending 'few ops' but the unit is bytes; a legitimately huge op (e.g. a large document mutation) landed in the log and now no projection page can pass over it with default limits.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17). Data as JSON: /api/errors/0e395e1e0f26d699. Report an issue: GitHub.

Appendix: source

Thrown at workers/sync-hub/src/do/SyncHub.ts:715

			projected,
			target,
			target,
			target,
			limit,
		).toArray();
		const ops: ChangeOp[] = [];
		for (const row of rows) {
			const op = toChange(row);
			const candidate = [...ops, op];
			const bytes = projectionRequestBytes({
				userId,
				epoch,
				fromSeqExclusive: projected,
				throughSeq: op.seq,
				ops: candidate,
			});
			if (bytes > byteLimit) {
				if (ops.length === 0) throw projectionError("one operation exceeds projection request byte budget");
				break;
			}
			ops.push(op);
		}
		if (ops.length === 0 && compareCanonicalDecimals(projected, target) < 0) {
			throw projectionError("unprojected log gap");
		}
		this.renewProjectionLease(leaseToken, now);
		return {
			protocol_version: 1,
			epoch,
			from_seq_exclusive: projected,
			through_seq: ops.length > 0 ? ops[ops.length - 1].seq : projected,
			target_seq: target,
			ops,
		};
	}

View on GitHub (pinned to d8bc9755e7)