{"record":{"id":"5e7c974ceab7aa67","repo":"aeron-io/aeron","slug":"difference-greater-than-2-31-1-termid-termid-initialtermid","errorCode":null,"errorMessage":"difference greater than 2^31 - 1: termId=${termId} - initialTermId=${initialTermId}","messagePattern":"difference greater than 2\\^31 - 1: termId=(.+?) - initialTermId=(.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"aeron-client/src/main/java/io/aeron/ChannelUriStringBuilder.java","lineNumber":236,"sourceCode":"\n        if (CommonContext.UDP_MEDIA.equals(media) && (null == endpoint && null == controlEndpoint))\n        {\n            throw new IllegalArgumentException(\"either 'endpoint' or 'control' must be specified for UDP.\");\n        }\n\n        final boolean anyNonNull = null != initialTermId || null != termId || null != termOffset;\n        final boolean anyNull = null == initialTermId || null == termId || null == termOffset;\n        if (anyNonNull)\n        {\n            if (anyNull)\n            {\n                throw new IllegalArgumentException(\n                    \"either all or none of the parameters ['initialTermId', 'termId', 'termOffset'] must be provided\");\n            }\n\n            if (termId - initialTermId < 0)\n            {\n                throw new IllegalArgumentException(\n                    \"difference greater than 2^31 - 1: termId=\" + termId + \" - initialTermId=\" + initialTermId);\n            }\n\n            if (null != termLength && termOffset > termLength)\n            {\n                throw new IllegalArgumentException(\"termOffset=\" + termOffset + \" > termLength=\" + termLength);\n            }\n        }\n\n        return this;\n    }\n\n    /**\n     * Set the prefix for taking an additional action such as spying on an outgoing publication with \"aeron-spy\".\n     *\n     * @param prefix to be applied to the URI before the scheme.\n     * @return this for a fluent API.\n     * @see ChannelUri#SPY_QUALIFIER","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-client/src/main/java/io/aeron/ChannelUriStringBuilder.java#L218-L254","documentation":"Thrown by ChannelUriStringBuilder.validate() when a termId is provided together with an initialTermId, but termId - initialTermId is negative. Because Aeron term IDs are compared using wrapping 31-bit arithmetic, a negative raw difference is interpreted as a difference larger than 2^31 - 1, which cannot be represented. The builder rejects the URI rather than emitting a channel string the media driver would consider inconsistent.","triggerScenarios":"Calling validate() (or build() paths that validate) after setting initialPosition(...) or explicitly setting termId via termId(Integer) with a smaller value than the set initialTermId, e.g. builder.initialTermId(1000).termId(999).validate().","commonSituations":"Manually computing term IDs from a recording position and mis-ordering them; replaying a recording whose initial term id exceeds the target term id; copying parameters from an existing channel URI and editing termId downward.","solutions":["Ensure termId >= initialTermId when both are set (accounting for 31-bit wrap: use Aeron's wrappingCompare semantics).","Remove the explicit termId/termOffset/initialTermId set (use initialPosition instead) and let the builder derive consistent values.","If wrapping across 2^31 is intended, choose termId = initialTermId + delta such that the delta fits in positive 31-bit range."],"exampleFix":"// before\nbuilder.initialTermId(100).termId(90).validate();\n// after\nbuilder.initialTermId(100).termId(190).validate();","handlingStrategy":"validation","validationCode":"if (termId != null && initialTermId != null && (termId - initialTermId) < 0) { throw new IllegalArgumentException(\"termId must be >= initialTermId (31-bit wrap)\"); }","typeGuard":"boolean hasConsistentTermIds(Integer termId, Integer initialTermId) { return termId == null || initialTermId == null || Integer.compareUnsigned(termId - initialTermId, 1 << 31) < 0; }","tryCatchPattern":"try { uri = builder.validate().build(); } catch (IllegalArgumentException e) { /* fall back to initialPosition-derived term params */ }","preventionTips":["Prefer initialPosition(long, int, int) over manually setting termId/termOffset/initialTermId","Use Aeron's wrapping compare utilities when comparing term IDs","Never hand-edit termId in copied URIs without recomputing the delta"],"tags":["aeron","channel-uri","validation","configuration"],"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"}