{"record":{"id":"8d518799dccda74c","repo":"redis/jedis","slug":"discard-without-multi-8d5187","errorCode":null,"errorMessage":"DISCARD without MULTI","messagePattern":"DISCARD without MULTI","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/Transaction.java","lineNumber":224,"sourceCode":"          formatted.add(e);\n        }\n      }\n      return formatted;\n    } catch (JedisConnectionException jce) {\n      broken = true;\n      throw jce;\n    } finally {\n      inMulti = false;\n      inWatch = false;\n      pipelinedResponses.clear();\n      onAfterExec();\n    }\n  }\n\n  @Override\n  public String discard() {\n    if (!inMulti) {\n      throw new IllegalStateException(\"DISCARD without MULTI\");\n    }\n\n    try {\n      // ignore QUEUED (or ERROR)\n      // processPipelinedResponses(pipelinedResponses.size());\n      connection.getMany(1 + pipelinedResponses.size());\n\n      connection.sendCommand(DISCARD);\n\n      return connection.getStatusCodeReply();\n    } catch (JedisConnectionException jce) {\n      broken = true;\n      throw jce;\n    } finally {\n      inMulti = false;\n      inWatch = false;\n      pipelinedResponses.clear();\n      onAfterDiscard();","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/Transaction.java#L206-L242","documentation":"Thrown by Transaction.discard() when called outside an active MULTI block: inMulti is false because MULTI was never sent or the transaction was already executed/reset, so there is nothing for the server to DISCARD. It is a client-side state guard that avoids sending an invalid command sequence.","triggerScenarios":"Calling discard() on a Transaction created with doMulti=true before any commands (MULTI already implicit? no — discard before multi in manual mode), calling discard() twice, or calling discard() after exec() already closed the block.","commonSituations":"Cleanup/finally blocks that unconditionally call discard(); error-handling paths where the transaction never entered MULTI; double abort attempts.","solutions":["Only call discard() while the transaction is open (after multi(), before exec()).","Guard cleanup code with a flag or check before discarding.","If the block was already exec'd, discard is unnecessary — skip it.","Create a new Transaction if a fresh block is needed."],"exampleFix":"// before\nTransaction t = jedis.transaction(false);\nt.discard(); // throws: never in MULTI\n// after\nTransaction t = jedis.transaction(false);\nt.multi();\nt.set(\"k\", \"v\");\nt.discard();","handlingStrategy":"validation","validationCode":"boolean blockOpen = startedMulti && !executed;\nif (blockOpen) tx.discard();","typeGuard":null,"tryCatchPattern":"try {\n  tx.discard();\n} catch (IllegalStateException e) {\n  // block already closed; safe to ignore\n}","preventionTips":["Only discard an open MULTI block","Use a flag to track transaction state in cleanup paths","Avoid unconditional discard in finally blocks"],"tags":["transaction","multi-exec","discard","jedis"],"backgroundTag":"invalid-state-transition","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"}