{"record":{"id":"0c62b749c9c549ca","repo":"apache/cassandra","slug":"invalid-specification-spec-does-not-match","errorCode":null,"errorMessage":"Invalid specification: '${spec}'; does not match ${PARSE}","messagePattern":"Invalid specification: '(.+?)'; does not match (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/RetryStrategy.java","lineNumber":305,"sourceCode":"                        retries = Integer.parseInt(value);\n                        if (retries < 0)\n                            throw new IllegalArgumentException(\"Must permit at least one attempt (attempts=\" + value + \" supplied)\");\n                        break;\n                    case \"rnd\":\n                        if (randomizer != null)\n                            throw new IllegalArgumentException(\"Randomizer already specified, cannot re-specify: \" + value);\n                        randomizer = parseWaitRandomizer(value);\n                        break;\n                }\n                end = next;\n            }\n            if (end != spec.length())\n                spec = spec.substring(0, end);\n        }\n\n        Matcher m = PARSE.matcher(spec);\n        if (!m.matches())\n            throw new IllegalArgumentException(\"Invalid specification: '\" + spec + \"'; does not match \" + PARSE);\n\n        long minMin = parseInMicros(m.group(\"minmin\"), 0);\n        long maxMax = parseInMicros(m.group(\"maxmax\"), Long.MAX_VALUE);\n        Wait max = TimeoutStrategy.parseWait(m.group(\"max\"), latencies);\n        String minSpec = m.group(\"min\");\n        Wait min = minSpec == null ? null : TimeoutStrategy.parseWait(minSpec, latencies);\n        if (min == null && randomizer != null)\n            throw new IllegalArgumentException(\"Invalid to specify randomiser when no range specified: '\" + original + '\\'');\n        if (min instanceof Wait.Constant && minMin != 0)\n            throw new IllegalArgumentException(\"Invalid to specify an absolute minimum constant when the min bound is itself a constant: '\" + original + '\\'');\n        long maxMin = parseInMicros(m.group(\"maxmin\"), Long.MAX_VALUE);\n        if (min instanceof Wait.Constant && maxMin != Long.MAX_VALUE)\n            throw new IllegalArgumentException(\"Invalid to specify an absolute max(min) constant when the min bound is itself a constant: '\" + original + '\\'');\n        if (max instanceof Wait.Constant && maxMax != Long.MAX_VALUE)\n            throw new IllegalArgumentException(\"Invalid to specify an absolute maximum constant when the max bound is itself a constant: '\" + original + '\\'');\n        if (randomizer == null)\n            randomizer = randomizers.uniform();\n        return new RetryStrategy(randomizer, minMin, min, maxMin, max, maxMax, retries);","sourceCodeStart":287,"sourceCodeEnd":323,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/RetryStrategy.java#L287-L323","documentation":"After stripping trailing key=value modifiers, the remaining wait specification must fully match the RetryStrategy.PARSE regex (the '[min..]max[;bounds]' grammar with optional absolute min/max clamps). If it does not, RetryStrategy.parse() throws an IllegalArgumentException showing the spec and the expected pattern.","triggerScenarios":"RetryStrategy.parse(spec, latencies) where the wait part is malformed: empty string, \"100ms..\" without a max, misspelled units (\"100 MSECONDS\"), reversed range (\"1s..100ms\"), or leftover garbage after the modifier parser stops consuming the string.","commonSituations":"Hand-edited cassandra.yaml retry specs; specs copied between versions where the accepted grammar changed; trailing junk left after modifier parsing truncated the spec.","solutions":["Match the documented format: <min>..<max> with valid durations, e.g. \"100ms..1s\"","Check units are accepted by TimeoutStrategy.parseWait (us, ms, s, m)","Ensure the range is ordered min <= max if both bounds are given","Print the PARSE pattern included in the message and compare character by character with your spec"],"exampleFix":"// before\nRetryStrategy.parse(\"100 MSECONDS to 1s\", latencies);\n// after\nRetryStrategy.parse(\"100ms..1s\", latencies);","handlingStrategy":"try-catch","validationCode":"private static final Pattern SIMPLE_SPEC = Pattern.compile(\"(\\\\d+(us|ms|s|m))(\\\\.\\\\.(\\\\d+(us|ms|s|m)))?\");\nstatic boolean looksLikeValidWaitSpec(String spec) {\n    String waitPart = spec.split(\",\")[0];\n    return SIMPLE_SPEC.matcher(waitPart).matches();\n}","typeGuard":null,"tryCatchPattern":"try {\n    RetryStrategy strategy = RetryStrategy.parse(spec, latencies);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Invalid specification:\")) {\n        throw new ConfigurationException(\"Retry spec '\" + spec + \"' invalid; expected e.g. '100ms..1s[,key=value]'\");\n    }\n    throw e;\n}","preventionTips":["Follow the canonical form: [<min>..]<max>[,modifiers]","Use accepted duration units (us, ms, s, m) without spaces","Validate all retry specs in a startup config-check pass","Quote specs in YAML so whitespace does not corrupt them"],"tags":["configuration","parsing","regex","illegal-argument"],"backgroundTag":"invalid-argument-format","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}