{"record":{"id":"cbd258114e959f04","repo":"redis/jedis","slug":"max-attempts-must-be-positive-for-cluster-mode","errorCode":null,"errorMessage":"Max attempts must be positive for cluster mode","messagePattern":"Max attempts must be positive for cluster mode","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/builders/ClusterClientBuilder.java","lineNumber":145,"sourceCode":"    Duration effectiveMaxTotalRetriesDuration = (this.maxTotalRetriesDuration == null)\n        ? Duration.ofMillis((long) this.clientConfig.getSocketTimeoutMillis() * this.maxAttempts)\n        : this.maxTotalRetriesDuration;\n\n    return new ClusterCommandExecutor((ClusterConnectionProvider) this.connectionProvider,\n        this.maxAttempts, effectiveMaxTotalRetriesDuration, this.commandFlags);\n  }\n\n  @Override\n  protected void validateSpecificConfiguration() {\n    validateCommonConfiguration();\n\n    if (nodes == null || nodes.isEmpty()) {\n      throw new IllegalArgumentException(\n          \"At least one cluster node must be specified for cluster mode\");\n    }\n\n    if (maxAttempts <= 0) {\n      throw new IllegalArgumentException(\"Max attempts must be positive for cluster mode\");\n    }\n\n    if (maxTotalRetriesDuration != null && maxTotalRetriesDuration.isNegative()) {\n      throw new IllegalArgumentException(\n          \"Max total retries duration cannot be negative for cluster mode\");\n    }\n\n    if (topologyRefreshPeriod != null && topologyRefreshPeriod.isNegative()) {\n      throw new IllegalArgumentException(\n          \"Topology refresh period cannot be negative for cluster mode\");\n    }\n  }\n\n}\n","sourceCodeStart":127,"sourceCodeEnd":160,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/builders/ClusterClientBuilder.java#L127-L160","documentation":"The cluster builder's maxAttempts controls how many times command execution is retried on failures during topology/redirect handling. validateSpecificConfiguration() rejects values of zero or less, since a non-positive maxAttempts would make cluster command execution immediately give up or behave incorrectly.","triggerScenarios":"Calling RedisClusterClient.builder().maxAttempts(0) or .maxAttempts(-1) (e.g. maxAttempts read from a config file or computed value that resolves to 0 or a negative number), then build().","commonSituations":"maxAttempts loaded from properties/env where a missing value defaults to 0; user setting 0 believing it means 'unlimited retries'; sign error when computing attempts from a duration.","solutions":["Set maxAttempts to a positive integer, e.g. .maxAttempts(5) (the cluster default is 5).","Clamp or validate values loaded from configuration: maxAttempts = Math.max(1, configuredValue).","Do not use maxAttempts to disable retries; instead configure maxTotalRetriesDuration for time-bounded retrying."],"exampleFix":"// before\nint attempts = Integer.parseInt(props.getProperty(\"cluster.maxAttempts\", \"0\"));\nbuilder.maxAttempts(attempts).build(); // throws when 0\n// after\nint attempts = Math.max(1, Integer.parseInt(props.getProperty(\"cluster.maxAttempts\", \"5\")));\nbuilder.maxAttempts(attempts).build();","handlingStrategy":"validation","validationCode":"if (maxAttempts <= 0) {\n  throw new IllegalArgumentException(\"maxAttempts must be >= 1 (cluster default is 5)\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the cluster default (5) unless you have a measured reason to change it.","Clamp config-sourced values: maxAttempts = Math.max(1, value).","Never encode 'disable retries' as 0; use maxTotalRetriesDuration instead."],"tags":["jedis","cluster","builder","retry","configuration"],"backgroundTag":"invalid-config-value","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}