{"record":{"id":"ba50b1b7ba152622","repo":"aeron-io/aeron","slug":"terminated-prematurely","errorCode":null,"errorMessage":"Terminated prematurely","messagePattern":"Terminated prematurely","errorType":"validation","errorClass":"InvalidMessage","httpStatus":null,"severity":"error","filePath":"aeron-client/src/main/java/io/aeron/logging/DecodingState.java","lineNumber":51,"sourceCode":"    {\n        this.buffer = buffer;\n        this.offset = initialOffset;\n        this.length = length;\n        this.limit = offset + length;\n        this.terminated = false;\n    }\n\n    void reset()\n    {\n        wrap(null, 0, 0);\n    }\n\n    void incrementOffset(final int increment)\n    {\n        this.offset += increment;\n        if (this.limit < this.offset)\n        {\n            throw new InvalidMessage(\"Terminated prematurely\");\n        }\n    }\n\n    int remaining()\n    {\n        return this.limit - this.offset;\n    }\n\n    void ensureRemaining(final int count)\n    {\n        if (this.remaining() < count)\n        {\n            throw new InvalidMessage(\"Terminated prematurely\");\n        }\n    }\n\n    int offset()\n    {","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-client/src/main/java/io/aeron/logging/DecodingState.java#L33-L69","documentation":"DecodingState.incrementOffset advances the CBOR decode cursor and checks it against the buffer limit. If the increment would move the offset past the limit, the buffer is exhausted mid-message and InvalidMessage('Terminated prematurely') is thrown — the CBOR payload ended before the decoder expected it to.","triggerScenarios":"Any parse step (parseMessage, parseString, parseLong, parseBoolean, parseEntry, parseNumber) consuming more bytes than remain — e.g. a declared string/byte-array length larger than the actual remaining buffer, or a truncated capture buffer.","commonSituations":"Truncated event-log fragments passed to the decoder; a log header claiming more bytes than the buffer holds; off-by-one in slicing the buffer around the log record.","solutions":["Verify the buffer slice passed to the decoder covers the full record (use the encoded header's captureLength/length fields).","Check that the event log wasn't truncated by the capture-length cap when writing.","Add a remaining-bytes check before parsing variable-length fields.","Re-capture with a larger capture length if records are being cut off."],"exampleFix":"// before\ndecoder.decode(buffer, offset, buffer.capacity()); // limit beyond actual data\n// after\nfinal int limit = offset + CommonEventEncoder.encodedLength(captureLength);\nif (limit > buffer.capacity()) throw new IllegalArgumentException(\"buffer too small\");\ndecoder.decode(buffer, offset, limit);","handlingStrategy":"validation","validationCode":"if (limit - offset < minimumExpectedRecordLength)\n{\n    throw new IllegalArgumentException(\"buffer slice too small for record\");\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    cborDecoder.decode(buffer, offset, limit);\n}\ncatch (final InvalidMessage ex)\n{\n    LOGGER.warn(\"truncated CBOR record at \" + offset + \": \" + ex.getMessage());\n}","preventionTips":["Slice buffers using the header's encoded length, not capacity.","Increase MAX_CAPTURE_LENGTH config if records are routinely truncated.","Check remaining() before variable-length field reads.","Handle InvalidMessage per record rather than failing the whole log."],"tags":["cbor","decoding","truncated-input"],"backgroundTag":"invalid-argument-format","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}