Hmbown/CodeWhale · error · Error

Pet bucket exceeds the recording segment byte limit.

Error message

Pet bucket exceeds the recording segment byte limit.

What it means

During rotation the recorder encodes the bucket as the first row of a new segment (sequence 0); if that single encoded row already exceeds the configured max segment byte size, no segment could ever hold it, so it throws before creating any files.

Solutions

  1. Inspect the bucket payload and shrink oversized fields before appending.
  2. Increase the recorder's maxBytes segment limit to exceed one encoded row.
  3. Fix the producer that emits abnormally large buckets (cap string lengths at the source).
  4. If this is recurring, add a payload-size check in the producer before calling append().

Example fix

// before
createPetRecorder(path, { maxBytes: 64 });
// after
createPetRecorder(path, { maxBytes: 1024 * 1024 });
Defensive patterns

Strategy: validation

Validate before calling

const encoded = JSON.stringify(bucket) + '\n';
if (Buffer.byteLength(encoded) > maxBytes) throw new Error('bucket row exceeds segment limit; shrink payload or raise maxBytes');

Prevention

When it happens

Trigger: Appending a pet bucket whose JSONL encoding (all fields plus sequence and simTimeMs) is larger than maxBytes; a bucket carrying a very large string field or nested payload that inflates the row.

Common situations: Downsizing maxBytes below the size of already-produced buckets; a bug producing oversized bucket payloads (huge labels/notes); misconfigured segment limit after changing bucket schema.

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 Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/33f219834a4b8518. Report an issue: GitHub.

Appendix: source

Thrown at pet/scripts/lib/pet-recorder.mjs:111

      }
    }
    expectedMtime ??= (await output.stat({ bigint: true })).mtimeNs;
  } catch (error) { try { await output?.close(); } finally { lock.close(); } throw error; }
  return {
    async append(bucket) {
      if (!output || busy) throw new Error('Pet recorder is closed or already writing.');
      validatePetBucket(bucket);
      busy = true;
      try {
        await lock.check();
        const held = await output.stat({ bigint: true }), current = await lstat(path, { bigint: true });
        if (!current.isFile() || held.dev !== current.dev || held.ino !== current.ino || held.size !== BigInt(bytes) || held.mtimeNs !== expectedMtime)
          throw new Error('The live pet recording was changed or replaced externally; existing files were preserved.');
        const encode = seq => encodePetJSONL([{ ...bucket, sequence: seq, simTimeMs: seq * PET_BIN_MS }]);
        let row = encode(sequence), size = Buffer.byteLength(row);
        if (restart || sequence >= maxBuckets || bytes + size > maxBytes) {
          row = encode(0); size = Buffer.byteLength(row);
          if (size > maxBytes) throw new Error('Pet bucket exceeds the recording segment byte limit.');
          const temporary = resolve(dirname(path), `.${basename(path)}.next-${randomUUID()}`);
          const archive = `${path}.segment-${String(segment + 1).padStart(6, '0')}.jsonl`;
          let next, installed = false, created = false;
          try {
            next = await open(temporary, 'wx', 0o600); created = true;
            await next.writeFile(row); await next.sync();
            const nextIdentity = await next.stat({ bigint: true });
            await next.close(); next = undefined;
            await output.sync();
            // link is exclusive: a collision never replaces someone else's
            // archive. Persist this name before replacing the live pathname.
            await link(path, archive); await syncDirectory(dirname(path));
            // Windows can reject replacement while either writer handle is
            // open. Both files are synced and the old file is archived first.
            await output.close(); output = undefined;
            for (let attempt = 0; ; attempt++) {
              await lock.check();
              const destination = await lstat(path, { bigint: true });

View on GitHub (pinned to 433685b202)