{"record":{"id":"de2da426b6845f08","repo":"apache/cassandra","slug":"from-epoch-d-must-be-less-than-or-equal-to","errorCode":null,"errorMessage":"--from-epoch (%d) must be less than or equal to --to-epoch (%d)","messagePattern":"--from-epoch \\((.+?)\\) must be less than or equal to --to-epoch \\((.+?)\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/tools/OfflineClusterMetadataDump.java","lineNumber":454,"sourceCode":"        }\n\n        static private Epoch previousEpoch(Epoch epoch)\n        {\n            if (UPGRADE_GOSSIP.equals(epoch) || UPGRADE_STARTUP.equals(epoch))\n                return epoch;\n            if (EMPTY.equals(epoch) || FIRST.equals(epoch))\n                return EMPTY;\n            return Epoch.create(epoch.getEpoch() - 1);\n        }\n\n        /**\n         * Validates that the from-epoch is not greater than to-epoch.\n         */\n        protected void validateEpochRange(Long fromEpoch, Long toEpoch)\n        {\n            if (fromEpoch != null && toEpoch != null && fromEpoch > toEpoch)\n            {\n                throw new IllegalArgumentException(\n                    String.format(\"--from-epoch (%d) must be less than or equal to --to-epoch (%d)\",\n                                  fromEpoch, toEpoch));\n            }\n        }\n\n        /**\n         * Processes entries from an EntryHolder, detecting and reporting gaps in epochs.\n         */\n        @VisibleForTesting\n        static ImmutableList<Entry> processEntriesWithGapDetection(LogReader.EntryHolder entryHolder,\n                                                                   Epoch startEpoch,\n                                                                   Output out)\n        {\n            ImmutableList.Builder<Entry> entries = ImmutableList.builder();\n            Epoch prevEpoch = startEpoch;\n            List<String> gaps = new ArrayList<>();\n\n            for (Entry e : (Iterable<Entry>) entryHolder::iterator)","sourceCodeStart":436,"sourceCodeEnd":472,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/tools/OfflineClusterMetadataDump.java#L436-L472","documentation":"validateEpochRange guards the offline metadata dump's epoch window options. If both --from-epoch and --to-epoch are supplied and from is greater than to, the range is nonsensical and an IllegalArgumentException with the formatted values is thrown before any log reading starts.","triggerScenarios":"Invoking OfflineClusterMetadataDump with, e.g., --from-epoch 100 --to-epoch 50; also triggered when a caller passes reversed longs to validateEpochRange programmatically.","commonSituations":"Typo'd or swapped argument order in shell scripts; copy-paste of epoch values in the wrong order; automating dumps with computed epoch variables that got transposed.","solutions":["Swap the values so --from-epoch <= --to-epoch","Validate ordering in the wrapping script before invoking the tool","Omit one of the flags if you only need a lower or upper bound"],"exampleFix":"// before\n--from-epoch 100 --to-epoch 50\n// after\n--from-epoch 50 --to-epoch 100","handlingStrategy":"validation","validationCode":"if (fromEpoch != null && toEpoch != null && fromEpoch > toEpoch)\n    throw new IllegalArgumentException(\"--from-epoch must be <= --to-epoch\");","typeGuard":null,"tryCatchPattern":"try { dump.run(...); }\ncatch (IllegalArgumentException e) { System.err.println(\"Bad epoch range: \" + e.getMessage()); }","preventionTips":["Validate flag ordering in wrapper scripts before invoking the tool","Don't hardcode both epochs; derive them from a single source","Test offline tool invocations in CI"],"tags":["cli","validation","epoch","cassandra"],"backgroundTag":"invalid-argument-value","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}