{"record":{"id":"e396182d64ac1a68","repo":"aeron-io/aeron","slug":"either-all-or-none-of-the-parameters-initialtermid-termid","errorCode":null,"errorMessage":"either all or none of the parameters ['initialTermId', 'termId', 'termOffset'] must be provided","messagePattern":"either all or none of the parameters \\['initialTermId', 'termId', 'termOffset'\\] must be provided","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"aeron-client/src/main/java/io/aeron/ChannelUriStringBuilder.java","lineNumber":230,"sourceCode":"    public ChannelUriStringBuilder validate()\n    {\n        if (null == media)\n        {\n            throw new IllegalArgumentException(\"media type is mandatory\");\n        }\n\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","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/aeron-io/aeron/blob/6d60124e15e35c11b49ba2e3c2c2858a09a18803/aeron-client/src/main/java/io/aeron/ChannelUriStringBuilder.java#L212-L248","documentation":"The positioning triple initialTermId, termId, termOffset must be supplied either completely or not at all; validate() throws IllegalArgumentException when only a subset is set. Additionally, when all are provided, termId must be within 2^31-1 of initialTermId.","triggerScenarios":"Calling validate() with e.g. .initialTermId(x).termId(y) but no .termOffset(...) (anyNonNull && anyNull), or with termId < initialTermId so the difference is negative (\"difference greater than 2^31 - 1\" companion check).","commonSituations":"Replaying/recording code that restores a subset of the positioning params (e.g. only termOffset) from a catalog or config; integer-underflow when termId wrapped past initialTermId in long-running streams.","solutions":["Set all three params (initialTermId, termId, termOffset) together, or none of them","When reconstructing from a recording, read all three from the same source atomically","Validate ordering: termId must be >= initialTermId and within 2^31-1; guard with (termId - initialTermId) >= 0 before validating"],"exampleFix":"// before\nbuilder.initialTermId(0).termOffset(1024).validate(); // missing termId\n// after\nbuilder.initialTermId(0).termId(1).termOffset(1024).validate();","handlingStrategy":"validation","validationCode":"static void requireCompletePositioning(Long initialTermId, Long termId, Long termOffset) {\n    boolean any = initialTermId != null || termId != null || termOffset != null;\n    boolean all = initialTermId != null && termId != null && termOffset != null;\n    if (any && !all) throw new IllegalArgumentException(\"set all or none of initialTermId/termId/termOffset\");\n    if (all && termId - initialTermId < 0) throw new IllegalArgumentException(\"termId < initialTermId\");\n}","typeGuard":"static boolean positioningComplete(Long i, Long t, Long o) {\n    return (i == null && t == null && o == null) || (i != null && t != null && o != null);\n}","tryCatchPattern":"try {\n    builder.validate().build();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"either all or none of the parameters\")) {\n        throw new IllegalArgumentException(\"Positioning params must be set together: initialTermId, termId, termOffset\", e);\n    }\n    throw e;\n}","preventionTips":["Always set initialTermId, termId, and termOffset as a group from a single source (e.g. recording catalog)","Wrap arithmetic in long and check (termId - initialTermId) >= 0 to catch wraparound before validating","Omit all positioning params unless you specifically need a replay position — the defaults are usually correct"],"tags":["uri-builder","validation","replay","aeron"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"6d60124e15e35c11b49ba2e3c2c2858a09a18803","analyzedAt":"2026-09-12T11:17:07.683Z","contentChangedAt":"2026-09-12T11:17:07.683Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}