{"record":{"id":"777544d02067c8b0","repo":"aeron-io/aeron","slug":"keylength-exceeds-max-key-length-max-key-length","errorCode":null,"errorMessage":"${keyLength} exceeds max key length ${MAX_KEY_LENGTH}","messagePattern":"(.+?) exceeds max key length (.+?)","errorType":"validation","errorClass":"ClusterException","httpStatus":null,"severity":"error","filePath":"aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java","lineNumber":132,"sourceCode":"        final long logPosition,\n        final long timestamp,\n        final int clusterId,\n        final long... snapshotRecordingIds)\n    {\n        final ExpandableArrayBuffer buffer = new ExpandableArrayBuffer(256);\n\n        buffer.putLong(LEADERSHIP_TERM_ID_OFFSET, leadershipTermId);\n        buffer.putLong(LOG_POSITION_OFFSET, logPosition);\n        buffer.putLong(TIMESTAMP_OFFSET, timestamp);\n        buffer.putInt(CLUSTER_ID_OFFSET, clusterId);\n\n        final int serviceCount = snapshotRecordingIds.length;\n        buffer.putInt(SERVICE_COUNT_OFFSET, serviceCount);\n\n        final int keyLength = SNAPSHOT_RECORDING_IDS_OFFSET + (serviceCount * SIZE_OF_LONG);\n        if (keyLength > MAX_KEY_LENGTH)\n        {\n            throw new ClusterException(keyLength + \" exceeds max key length \" + MAX_KEY_LENGTH);\n        }\n\n        for (int i = 0; i < serviceCount; i++)\n        {\n            buffer.putLong(SNAPSHOT_RECORDING_IDS_OFFSET + (i * SIZE_OF_LONG), snapshotRecordingIds[i]);\n        }\n\n        final int labelOffset = BitUtil.align(keyLength, SIZE_OF_INT);\n        int labelLength = 0;\n        labelLength += buffer.putStringWithoutLengthAscii(labelOffset + labelLength, NAME);\n        labelLength += buffer.putLongAscii(keyLength + labelLength, leadershipTermId);\n        labelLength += buffer.putStringWithoutLengthAscii(labelOffset + labelLength, \" logPosition=\");\n        labelLength += buffer.putLongAscii(labelOffset + labelLength, logPosition);\n        labelLength += buffer.putStringWithoutLengthAscii(labelOffset + labelLength, \" clusterId=\");\n        labelLength += buffer.putIntAscii(labelOffset + labelLength, clusterId);\n\n        return aeron.addCounter(RECOVERY_STATE_TYPE_ID, buffer, 0, keyLength, buffer, labelOffset, labelLength);\n    }","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-cluster/src/main/java/io/aeron/cluster/service/RecoveryState.java#L114-L150","documentation":"RecoveryState.allocate encodes the snapshotRecordingIds array into a counter's key. The total key length (fixed header plus one long per service) must fit within MAX_KEY_LENGTH (the counter key capacity). If serviceCount is too large, the computed keyLength overflows the key and this ClusterException is thrown before writing.","triggerScenarios":"Calling RecoveryState.allocate with a snapshotRecordingIds array whose length (service count) makes SNAPSHOT_RECORDING_IDS_OFFSET + serviceCount * SIZE_OF_LONG exceed MAX_KEY_LENGTH.","commonSituations":"Running a cluster configured with an extremely large services count (aeron.cluster.services.count or many registered services) exceeding Aeron counter key capacity; misconfigured counter key buffer size.","solutions":["Reduce the number of clustered services in the container configuration.","Do not pass more recording IDs than the service count / shrink the snapshotRecordingIds array.","Increase the counters key capacity only if you control the Aeron counters manager buffer sizes.","Check for a bug passing the wrong array (e.g. unbounded list) to allocate."],"exampleFix":"// before\nRecoveryState.allocate(countersManager, tempBuffer, Integer.MAX_VALUE, snapshotIds, ...);\n// after\nif (snapshotIds.length <= MAX_SERVICES) {\n    RecoveryState.allocate(countersManager, tempBuffer, recoverable, snapshotIds, ...);\n}","handlingStrategy":"validation","validationCode":"int keyLength = RecoveryState.SNAPSHOT_RECORDING_IDS_OFFSET + serviceCount * Long.BYTES;\nif (keyLength > RecoveryState.MAX_KEY_LENGTH) {\n    throw new IllegalArgumentException(\"too many services: \" + serviceCount);\n}","typeGuard":null,"tryCatchPattern":"try {\n    RecoveryState.allocate(countersManager, tempBuffer, snapshotIds, ...);\n} catch (ClusterException e) {\n    if (e.getMessage().contains(\"exceeds max key length\")) {\n        // reduce service count or fail fast with clearer message\n    } else {\n        throw e;\n    }\n}","preventionTips":["Cap configured service count below the key-capacity limit (64 / 8 minus header entries).","Pass exactly the configured service count of recording IDs to allocate.","Assert array length in configuration loading, not at allocation time."],"tags":["aeron","cluster","counter","key-length","recovery"],"backgroundTag":"value-out-of-range","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"}