aeron-io/aeron · error · InvalidMessage

Expected boolean

Error message

Expected boolean

What it means

CborDecode.parseBoolean expects a CBOR major type 7 (simple value) with additional content 20 (false) or 21 (true). Any other type at the current offset — including null, undefined, or an integer — triggers InvalidMessage('Expected boolean'). The binary stream deviates from the expected logger field layout.

Solutions

  1. Confirm the decoder and logger versions match and restart decode from the beginning of the stream
  2. Check the source file/buffer for truncation or corruption before decoding
  3. Catch CborDecode.InvalidMessage around field parses and resynchronize or abort with offset context

Example fix

// before
final boolean truncated = cborDecode.parseBoolean(state);
// after
final int typeByte = state.peekByte(); // validate major type 7 (0xE0-0xFF range) before parsing
final boolean truncated = cborDecode.parseBoolean(state);
Defensive patterns

Strategy: try-catch

Validate before calling

// peek major type 7 (0xE0..0xF8) before parsing a boolean
final int typeByte = state.buffer().getByte(state.offset());
final boolean looksBoolean = (typeByte & 0xE0) == 0xE0;

Try / catch

try { final boolean truncated = cborDecode.parseBoolean(state); } catch (final CborDecode.InvalidMessage ex) { throw new LogDecodeException("expected CBOR boolean at offset " + state.offset(), ex); }

Prevention

When it happens

Trigger: Decoding a logger stream where a boolean field (e.g. 'truncated') is absent, corrupted, or replaced by another CBOR type due to version mismatch or stream corruption/misalignment.

Common situations: Replaying truncated recordings, decoding logs written by a newer Aeron logger with extra fields, or resuming decode mid-item after an earlier parse error.

Related errors


AI-assisted analysis of aeron-io/aeron@6d60124e15 (2026-09-12). Data as JSON: /api/errors/54fcd01698518649. Report an issue: GitHub.

Appendix: source

Thrown at aeron-client/src/main/java/io/aeron/logging/CborDecode.java:150

        {
            throw new InvalidMessage("Expected timestamp");
        }

        return parseNumber(state, majorType, additionalContent);
    }

    private boolean parseBoolean(final DecodingState state)
    {
        state.ensureRemaining(1);
        final int typeByte = (0xFF) & state.buffer().getByte(state.offset());
        state.incrementOffset(1);
        final int majorType = majorType(typeByte);
        final int additionalContent = additionalContent(typeByte);

        if (SIMPLE_VALUE_MAJOR_TYPE != majorType ||
            (ADDITIONAL_CONTENT_TRUE != additionalContent && ADDITIONAL_CONTENT_FALSE != additionalContent))
        {
            throw new InvalidMessage("Expected boolean");
        }

        return additionalContent == ADDITIONAL_CONTENT_TRUE;
    }

    private void parseSimpleValue(final DecodingState state, final int additionalContent)
    {
        switch (additionalContent)
        {
            case ADDITIONAL_CONTENT_FALSE:
            case ADDITIONAL_CONTENT_TRUE:
                for (int i = 0, n = loggers.size(); i < n; i++)
                {
                    final LoggerEventCallback logger = loggers.get(i);
                    logger.onValue(keyAsciiView, NO_TAG, additionalContent == ADDITIONAL_CONTENT_TRUE);
                }
                break;
            case ADDITIONAL_CONTENT_NULL:

View on GitHub (pinned to 6d60124e15)