{"record":{"id":"21f46e8b2cfef8e8","repo":"redis/jedis","slug":"failover-with-force-option-requires-both-a-timeout","errorCode":null,"errorMessage":"FAILOVER with force option requires both a timeout and target HOST and IP.","messagePattern":"FAILOVER with force option requires both a timeout and target HOST and IP\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/params/FailoverParams.java","lineNumber":54,"sourceCode":"    this.force = true;\n    return this;\n  }\n\n  public FailoverParams timeout(long timeout) {\n    this.timeout = timeout;\n    return this;\n  }\n\n  @Override\n  public void addParams(CommandArguments args) {\n\n    if (to != null) {\n      args.add(Keyword.TO).add(to.getHost()).add(to.getPort());\n    }\n\n    if (force) {\n      if (to == null || timeout == null) {\n        throw new IllegalArgumentException(\"FAILOVER with force option requires both a timeout and target HOST and IP.\");\n      }\n      args.add(Keyword.FORCE);\n    }\n\n    if (timeout != null) {\n      args.add(Keyword.TIMEOUT).add(timeout);\n    }\n\n  }\n\n  @Override\n  public boolean equals(Object o) {\n    if (this == o) return true;\n    if (o == null || getClass() != o.getClass()) return false;\n    FailoverParams that = (FailoverParams) o;\n    return force == that.force && Objects.equals(to, that.to) && Objects.equals(timeout, that.timeout);\n  }\n","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/params/FailoverParams.java#L36-L72","documentation":"CLUSTER FAILOVER with the FORCE option mandates, per the Redis protocol, both a TIMEOUT and a target (TO host:port). FailoverParams.addParams enforces this: if force is set but either to or timeout is missing, it throws IllegalArgumentException explaining the requirement before emitting the FORCE keyword.","triggerScenarios":"Calling failover with failoverParams.force() (or force(true)) but omitting to(host,port) or timeout(duration); e.g. FailoverParams.failoverParams().force().build() without TO/TIMEOUT.","commonSituations":"Translating a CLI FAILOVER FORCE invocation (which needs no TO on a replica) directly into the client API without adding TO and TIMEOUT; copying force() from examples that also set TO/TIMEOUT out of frame; building params conditionally where TO/TIMEOUT branches were not taken.","solutions":["Provide both to(host, port) and timeout(duration) whenever force() is used.","If no target is intended, drop the force option and use a plain/takeover failover instead.","Validate params construction order in helper code so force() is only reachable after to()/timeout() are set."],"exampleFix":"// before\nFailoverParams params = FailoverParams.FailoverParamsBuilder\n    .force().build(); // missing TO and TIMEOUT\n// after\nFailoverParams params = FailoverParams.FailoverParamsBuilder\n    .to(\"127.0.0.1\", 6380)\n    .timeout(Duration.ofSeconds(60))\n    .force().build();","handlingStrategy":"validation","validationCode":"if (useForce && (targetHost == null || targetPort <= 0 || timeoutMs <= 0)) {\n  throw new IllegalArgumentException(\"FAILOVER force requires TO host:port and TIMEOUT\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  jedis.failover(params);\n} catch (IllegalArgumentException e) {\n  // rebuild params with to() + timeout(), or retry without force\n}","preventionTips":["Whenever force() is used, set to(host, port) and timeout(duration) in the same builder chain.","Remember the client API enforces the TO/TIMEOUT requirement even where the CLI does not.","Add a unit test asserting force always yields a params object containing TO and TIMEOUT."],"tags":["params","failover","cluster","illegal-argument"],"backgroundTag":"missing-required-argument","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"}