{"id":"66355ea5ed8ff12d","repo":"apache/kafka","slug":"invalid-partition-d-partition-number-should-alw","errorCode":null,"errorMessage":"Invalid partition: %d. Partition number should always be non-negative or null.","messagePattern":"Invalid partition: (.+?)\\. Partition number should always be non-negative or null\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/producer/ProducerRecord.java","lineNumber":78,"sourceCode":"    /**\n     * Creates a record with a specified timestamp to be sent to a specified topic and partition\n     * \n     * @param topic The topic the record will be appended to\n     * @param partition The partition to which the record should be sent\n     * @param timestamp The timestamp of the record, in milliseconds since epoch. If null, the producer will assign\n     *                  the timestamp using System.currentTimeMillis().\n     * @param key The key that will be included in the record\n     * @param value The record contents\n     * @param headers the headers that will be included in the record\n     */\n    public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value, Iterable<Header> headers) {\n        if (topic == null)\n            throw new IllegalArgumentException(\"Topic cannot be null.\");\n        if (timestamp != null && timestamp < 0)\n            throw new IllegalArgumentException(\n                    String.format(\"Invalid timestamp: %d. Timestamp should always be non-negative or null.\", timestamp));\n        if (partition != null && partition < 0)\n            throw new IllegalArgumentException(\n                    String.format(\"Invalid partition: %d. Partition number should always be non-negative or null.\", partition));\n        this.topic = topic;\n        this.partition = partition;\n        this.key = key;\n        this.value = value;\n        this.timestamp = timestamp;\n        this.headers = new RecordHeaders(headers);\n    }\n\n    /**\n     * Creates a record with a specified timestamp to be sent to a specified topic and partition\n     *\n     * @param topic The topic the record will be appended to\n     * @param partition The partition to which the record should be sent\n     * @param timestamp The timestamp of the record, in milliseconds since epoch. If null, the producer will assign the\n     *                  timestamp using System.currentTimeMillis().\n     * @param key The key that will be included in the record\n     * @param value The record contents","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/producer/ProducerRecord.java#L60-L96","documentation":"Thrown by the ProducerRecord constructor when an explicit partition number is supplied that is negative. Partition numbers in Kafka are 0-indexed; the producer accepts either null (to let the partitioner choose) or a non-negative integer. A negative partition would never map to a real partition, so it is rejected at construction as an IllegalArgumentException.","triggerScenarios":"Calling a ProducerRecord constructor with a negative Integer partition, e.g. new ProducerRecord<>(topic, -1, key, value). Commonly seen when callers use -1 as a 'let the partitioner decide' marker instead of passing null.","commonSituations":"Confusing the producer's API (which uses null for unspecified partition) with libraries or APIs that use -1 as a sentinel; computing a partition from a hash or modulo that returned -1 due to a bug; reading partition from a config that defaults to -1; porting code from a client in another language whose convention is -1 for unset.","solutions":["Pass null instead of a negative number when you want the partitioner to choose: new ProducerRecord<>(topic, null, key, value).","Validate the partition before construction: Integer p = (partition == null || partition < 0) ? null : partition.","If the partition comes from a config that uses -1 as 'unset', translate it to null at the config boundary so -1 never reaches the constructor."],"exampleFix":"// before\nint partition = config.getInt(\"partition\", -1);\nnew ProducerRecord<>(topic, partition, key, value);\n\n// after\nint raw = config.getInt(\"partition\", -1);\nInteger partition = raw < 0 ? null : raw;\nnew ProducerRecord<>(topic, partition, key, value);","handlingStrategy":"validation","validationCode":"// Partition must be null (let the partitioner choose) or >= 0.\nInteger partition = /* intended partition */;\nif (partition != null && partition < 0) {\n    throw new IllegalArgumentException(\"partition must be non-negative or null, got \" + partition);\n}\nProducerRecord<K, V> record = new ProducerRecord<>(topic, partition, timestamp, key, value);","typeGuard":"// Narrows an Integer to a valid partition sentinel or concrete partition.\nstatic Integer requireValidPartition(Integer p, int numPartitions) {\n    if (p != null) {\n        if (p < 0) throw new IllegalArgumentException(\"negative partition: \" + p);\n        if (p >= numPartitions) throw new IllegalArgumentException(\"partition \" + p + \" >= numPartitions \" + numPartitions);\n    }\n    return p;\n}","tryCatchPattern":"try {\n    ProducerRecord<K, V> r = new ProducerRecord<>(topic, partition, timestamp, key, value);\n    producer.send(r);\n} catch (IllegalArgumentException e) {\n    // Fall back to null partition so the built-in partitioner picks one\n    ProducerRecord<K, V> fallback = new ProducerRecord<>(topic, null, timestamp, key, value);\n    producer.send(fallback);\n}","preventionTips":["Prefer null partition unless you have an explicit routing reason.","When assigning partitions manually, refresh metadata and re-check against current partition count (topics can be resized).","Never use -1 as a sentinel for 'no partition'; use null.","Encapsulate partition selection so the upper layers can't pass unvalidated integers."],"tags":["kafka","java","producer","validation","partition"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}