{"id":"e0dd0afe9f54d95a","repo":"apache/kafka","slug":"invalid-serialized-transaction-state-format-ser","errorCode":null,"errorMessage":"Invalid serialized transaction state format: ${serializedState}","messagePattern":"Invalid serialized transaction state format: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/producer/PreparedTxnState.java","lineNumber":55,"sourceCode":"    }\n\n    /**\n     * Creates a new PreparedTxnState from a serialized string representation\n     *\n     * @param serializedState               The serialized string to deserialize.\n     * @throws IllegalArgumentException if the serialized string is not in the expected format\n     */\n    public PreparedTxnState(String serializedState) {\n        if (serializedState == null || serializedState.isEmpty()) {\n            this.producerId = RecordBatch.NO_PRODUCER_ID;\n            this.epoch = RecordBatch.NO_PRODUCER_EPOCH;\n            return;\n        }\n\n        try {\n            String[] parts = serializedState.split(\":\");\n            if (parts.length != 2) {\n                throw new IllegalArgumentException(\"Invalid serialized transaction state format: \" + serializedState);\n            }\n\n            this.producerId = Long.parseLong(parts[0]);\n            this.epoch = Short.parseShort(parts[1]);\n\n            // Validate the producerId and epoch values.\n            if (!(this.producerId >= 0 && this.epoch >= 0)) {\n                throw new IllegalArgumentException(\"Invalid producer ID and epoch values: \" +\n                    producerId + \":\" + epoch + \". Both must be >= 0\");\n            }\n        } catch (NumberFormatException e) {\n            throw new IllegalArgumentException(\"Invalid serialized transaction state format: \" + serializedState, e);\n        }\n    }\n\n    /**\n     * Creates a new PreparedTxnState with the given producer ID and epoch\n     *","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/producer/PreparedTxnState.java#L37-L73","documentation":"Thrown by the PreparedTxnState(String) constructor as an IllegalArgumentException when the serialized string cannot be parsed into the expected \"producerId:epoch\" form. The constructor splits on ':' and requires exactly two non-negative numeric parts; a wrong part count, non-numeric content, or negative values all funnel into this message (the NumberFormatException from Long.parseLong/Short.parseShort is caught and rethrown as the same IllegalArgumentException at line 67). It guards deserialization of prepared-transaction state shared across process restarts or test fixtures.","triggerScenarios":"Constructing new PreparedTxnState(serialized) where serialized is non-empty and (a) does not contain exactly one ':' (so parts.length != 2), (b) either side fails Long.parseLong/Short.parseShort, or (c) parses but producerId<0 or epoch<0. Reached at line 55 (format mismatch) or line 67 (numeric failure).","commonSituations":"Persisting PreparedTxnState.toString() and loading it back with a corrupt/truncated value; a test fixture or config file providing a malformed string like \"1000\" or \"1000:1:0\" or \"abc:2\"; cross-version mismatch where an older format is read by newer code that expects exactly two fields; user-supplied input passed straight into the constructor without validation.","solutions":["Produce the serialized form only via PreparedTxnState.toString() (format \"producerId:epoch\", or empty for uninitialized) so the round-trip is guaranteed.","Validate the input before constructing: non-empty, matches regex ^\\d+:\\d+$, and both values >= 0; reject early with a domain-meaningful error.","If loading from persistent storage, wrap the constructor call in try/catch(IllegalArgumentException) and treat the record as uninitialized (use the no-arg PreparedTxnState() or pass empty string).","Fix the source of the malformed value (fixture/config/serialization layer) rather than silently defaulting, to avoid masking real corruption."],"exampleFix":"// before\nPreparedTxnState s = new PreparedTxnState(\"1000-1\"); // IllegalArgumentException\n\n// after\nPreparedTxnState s = new PreparedTxnState(\"1000:1\");\n// or round-trip safely:\nString stored = existingState.toString();\nPreparedTxnState s = stored.isEmpty() ? new PreparedTxnState() : new PreparedTxnState(stored);","handlingStrategy":"validation","validationCode":"import java.util.regex.Pattern;\n\nstatic final Pattern STATE_RE = Pattern.compile(\"^\\\\d+:\\\\d+$\");\n\nboolean isValidSerializedState(String s) {\n    if (s == null || s.isEmpty()) return true; // empty == uninitialized, allowed\n    if (!STATE_RE.matcher(s).matches()) return false;\n    String[] parts = s.split(\":\");\n    try {\n        long pid = Long.parseLong(parts[0]);\n        short ep = Short.parseShort(parts[1]);\n        return pid >= 0 && ep >= 0;\n    } catch (NumberFormatException e) {\n        return false;\n    }\n}\n\n// usage:\nif (!isValidSerializedState(input)) {\n    throw new IllegalArgumentException(\"Bad state string: \" + input);\n}\nPreparedTxnState state = new PreparedTxnState(input);","typeGuard":null,"tryCatchPattern":"try {\n    PreparedTxnState state = new PreparedTxnState(serialized);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Invalid serialized transaction state format\")) {\n        // log and reject the input; do not proceed with a default state\n    } else {\n        throw e;\n    }\n}","preventionTips":["Only feed strings produced by PreparedTxnState.toString() back into the String constructor; round-trip your own output.","Validate the 'producerId:epoch' format with a regex before constructing.","Treat null/empty as a deliberate 'uninitialized' marker; reject everything else that fails the regex.","Never accept serialized state from untrusted input — it is a compact, single-colon pair only."],"tags":["prepared-txn-state","deserialization","validation","transactions"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}