{"record":{"id":"3ae83142ef552faa","repo":"Hmbown/CodeWhale","slug":"live-pet-input-exceeds-its-tail-limit","errorCode":null,"errorMessage":"Live pet input exceeds its tail limit.","messagePattern":"Live pet input exceeds its tail limit\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1136,"sourceCode":"        throw new Error('Pet tape exceeds 24 hours.');\n    return rows.map((row, i) => { validatePetBucket(row); if (row.sequence !== i)\n        throw new Error('Non-contiguous pet tape.'); return row; });\n}\n/** A live file must advance before its contents count as a new observation.\n * Existing bytes, duplicate samples and a restarted sequence establish a\n * baseline; they never replay an old onset or human request. Drivers supply a\n * bounded tail and reset this cursor after suspension or a new attachment. */\nclass PetLiveTape {\n    sequence;\n    reset() { this.sequence = undefined; }\n    readTail(text) {\n        if (!text) {\n            this.reset();\n            return;\n        }\n        if (text.length > 262_144) {\n            this.reset();\n            throw new Error('Live pet input exceeds its tail limit.');\n        }\n        if (!text.endsWith('\\n'))\n            return;\n        const line = text.trimEnd().split('\\n').at(-1);\n        if (!line)\n            return;\n        let packet;\n        try {\n            packet = JSON.parse(line);\n            validatePetBucket(packet);\n        }\n        catch (error) {\n            this.reset();\n            throw error;\n        }\n        const previous = this.sequence;\n        this.sequence = packet.sequence;\n        if (previous === undefined || packet.sequence <= previous)","sourceCodeStart":1118,"sourceCodeEnd":1154,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1118-L1154","documentation":"PetLiveTape.push() only accepts a bounded tail of live input (256 KiB). If the supplied text chunk exceeds 262,144 bytes it resets the cursor state and throws, because a chunk that large cannot be a bounded tail of recent lines.","triggerScenarios":"Calling the live-tape driver (PetLiveTape push/read) with a text chunk longer than 262,144 bytes — e.g. passing the whole log file instead of a recent tail, or a single unbounded read of a fast-growing file.","commonSituations":"Driver implementation bug reading the entire file on first attach; a tape file that grew huge between polls so a delta read returns everything; passing accumulated buffer instead of the tail slice.","solutions":["Slice the input to the last 262,144 bytes before handing it to the live tape (e.g. text.slice(-262_144)).","Fix the driver to supply a bounded tail per the PetLiveTape contract and reset the cursor after suspension.","Poll more frequently so per-chunk deltas stay under the tail limit.","After the throw, re-attach with a fresh baseline: pass '' first (reset), then feed bounded tails."],"exampleFix":"// before\nliveTape.push(fs.readFileSync('pet.log', 'utf8')); // throws when file > 256 KiB\n// after\nconst text = fs.readFileSync('pet.log', 'utf8');\nliveTape.push(text.slice(-262_144));","handlingStrategy":"validation","validationCode":"function isBoundedTail(text) {\n  return typeof text === 'string' && Buffer.byteLength(text, 'utf8') <= 262_144;\n}\nif (!isBoundedTail(chunk)) chunk = chunk.slice(-262_144);","typeGuard":"function isTailSafe(text) {\n  return typeof text === 'string' && text.length <= 262_144;\n}","tryCatchPattern":"try {\n  liveTape.push(chunk);\n} catch (e) {\n  if (e.message.includes('tail limit')) {\n    liveTape.push('');            // reset baseline\n    liveTape.push(chunk.slice(-262_144));\n  } else throw e;\n}","preventionTips":["Always slice reads to a bounded tail (last 256 KiB) before pushing.","Reset the live-tape cursor after suspension or re-attachment, per its contract.","Poll frequently enough that deltas stay small.","Never feed the entire file into the live path; the full-file path is decodePetJSONL."],"tags":["input-validation","size-limit","streaming"],"backgroundTag":"payload-too-large","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}