aeron-io/aeron · error · util::IllegalArgumentException

EINVAL

EINVAL

Error message

counter id {id} out of range: maxCounterId={maxCounterId}

What it means

CountersReader::getCounterState() validates the counter id via the C API and throws IllegalArgumentException (EINVAL) when the id is outside the valid range (0 .. maxCounterId()-1, derived from the counter metadata buffer size). The underlying aeron_counters_reader_counter_state returns < 0 for any id that has no metadata slot.

Solutions

  1. Validate 0 <= id < countersReader.maxCounterId() before any counter lookup.
  2. Look up counters by label/typeId via forEach/findByLabel instead of persisted raw ids.
  3. Re-acquire counter ids from the current driver session after a restart rather than reusing cached values.
  4. Check for negative ids from signed arithmetic before calling the API.

Example fix

// before
auto state = countersReader.getCounterState(cachedId); // cachedId may be stale
// after
if (cachedId < 0 || cachedId >= countersReader.maxCounterId())
    throw std::runtime_error("counter id out of range");
auto state = countersReader.getCounterState(cachedId);
Defensive patterns

Strategy: validation

Validate before calling

bool counterIdValid(const aeron::concurrent::CountersReader& r, std::int32_t id) {
    return id >= 0 && id < r.maxCounterId();
}

Try / catch

try {
    auto state = countersReader.getCounterState(id);
} catch (const aeron::util::IllegalArgumentException& e) {
    // id stale/out of range: re-enumerate counters via for-each
}

Prevention

When it happens

Trigger: Calling getCounterState(), getRecordingId(), getSourceIdentity(), isActive(), or byCounterId-style iteration with id < 0 or id >= maxCounterId(); using a counter id from a different, stale Aeron client or a different media driver run.

Common situations: Persisting counter ids across driver restarts; iterating with an upper bound taken from a different CountersReader; sign errors making id negative; hard-coded counter ids that depend on allocation order.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

Thrown at aeron-client/src/main/cpp_wrapper/concurrent/CountersReader.h:191

    inline std::int64_t getCounterOwnerId(std::int32_t id) const
    {
        validateCounterId(id);

        std::int64_t ownerId;
        if (aeron_counters_reader_counter_owner_id(m_countersReader, id, &ownerId) < 0)
        {
            AERON_MAP_ERRNO_TO_SOURCED_EXCEPTION_AND_THROW;
        }

        return ownerId;
    }

    inline std::int32_t getCounterState(std::int32_t id) const
    {
        std::int32_t state;
        if (aeron_counters_reader_counter_state(m_countersReader, id, &state) < 0)
        {
            throw util::IllegalArgumentException(
                "counter id " + std::to_string(id) +
                " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                SOURCEINFO, EINVAL);
        }

        return state;
    }

    inline std::int32_t getCounterTypeId(std::int32_t id) const
    {
        std::int32_t typeId;
        if (aeron_counters_reader_counter_type_id(m_countersReader, id, &typeId) < 0)
        {
            throw util::IllegalArgumentException(
                "counter id " + std::to_string(id) +
                " out of range: maxCounterId=" + std::to_string(maxCounterId()),
                SOURCEINFO, EINVAL);
        }

View on GitHub (pinned to 6d60124e15)