apache/kafka · error · IllegalArgumentException
Invalid timestamp: %d. Timestamp should always be non-negati
Error message
Invalid timestamp: %d. Timestamp should always be non-negative or null.
What it means
Thrown by the ProducerRecord constructor when a non-null timestamp is negative. The producer accepts either null (it will stamp the record with current time) or a non-negative millisecond epoch value; a negative value would produce an invalid record timestamp and is rejected at construction with an IllegalArgumentException.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/producer/ProducerRecord.java:75
private final V value;
private final Long timestamp;
/**
* Creates a record with a specified timestamp to be sent to a specified topic and partition
*
* @param topic The topic the record will be appended to
* @param partition The partition to which the record should be sent
* @param timestamp The timestamp of the record, in milliseconds since epoch. If null, the producer will assign
* the timestamp using System.currentTimeMillis().
* @param key The key that will be included in the record
* @param value The record contents
* @param headers the headers that will be included in the record
*/
public ProducerRecord(String topic, Integer partition, Long timestamp, K key, V value, Iterable<Header> headers) {
if (topic == null)
throw new IllegalArgumentException("Topic cannot be null.");
if (timestamp != null && timestamp < 0)
throw new IllegalArgumentException(
String.format("Invalid timestamp: %d. Timestamp should always be non-negative or null.", timestamp));
if (partition != null && partition < 0)
throw new IllegalArgumentException(
String.format("Invalid partition: %d. Partition number should always be non-negative or null.", partition));
this.topic = topic;
this.partition = partition;
this.key = key;
this.value = value;
this.timestamp = timestamp;
this.headers = new RecordHeaders(headers);
}
/**
* Creates a record with a specified timestamp to be sent to a specified topic and partition
*
* @param topic The topic the record will be appended to
* @param partition The partition to which the record should be sent
* @param timestamp The timestamp of the record, in milliseconds since epoch. If null, the producer will assign theView on GitHub (pinned to c31c9215e1)
Solutions
- Pass null instead of a negative sentinel when you have no timestamp; the producer will assign System.currentTimeMillis() for you.
- Sanitize upstream timestamps before construction: long ts = sourceTs != null && sourceTs >= 0 ? sourceTs : null; then build the ProducerRecord.
- If using a custom/mock clock in tests, ensure it returns a non-negative epoch millis value, or inject null for the timestamp in test fixtures.
Example fix
// before long ts = event.getEventTime(); // returns -1 when unknown new ProducerRecord<>(topic, partition, ts, key, value); // after Long ts = event.getEventTime(); if (ts != null && ts < 0) ts = null; new ProducerRecord<>(topic, partition, ts, key, value);
Defensive patterns
Strategy: validation
Validate before calling
// Timestamp must be null or >= 0 (ms since epoch).
Long timestamp = /* source timestamp */;
if (timestamp != null && timestamp < 0L) {
throw new IllegalArgumentException("timestamp must be non-negative or null, got " + timestamp);
}
ProducerRecord<K, V> record = new ProducerRecord<>(topic, partition, timestamp, key, value); Type guard
// Narrows a Long to a valid producer timestamp (null OR non-negative).
static Long requireValidTimestamp(Long ts) {
if (ts != null && ts < 0L) throw new IllegalArgumentException("negative timestamp: " + ts);
return ts;
} Try / catch
try {
ProducerRecord<K, V> r = new ProducerRecord<>(topic, partition, timestamp, key, value);
producer.send(r);
} catch (IllegalArgumentException e) {
// Either drop the record or re-stamp with System.currentTimeMillis() and retry build
} Prevention
- Prefer passing null (let the producer stamp it) unless you have a real event-time source.
- When sourcing timestamps from external systems, sanitize: clamp negatives to null, not to 0.
- Guard clock extraction (e.g. parsing failures returning -1) before building the record.
- Unit-test the record-building layer with boundary inputs (-1L, 0L, now, null).
When it happens
Trigger: Calling any ProducerRecord constructor that takes a Long timestamp with a negative value, e.g. new ProducerRecord<>(topic, partition, -1L, key, value). Also when the timestamp is derived from System.currentTimeMillis() under a clock skew or mock clock returning negative values, or from a domain field that was never validated and was set to -1 as a sentinel.
Common situations: Using -1L or 0L-minus-one as a 'no timestamp' sentinel instead of null; consuming a timestamp from an upstream system (e.g. CDC, database column) that uses 0 or negative for missing values; testing with a mocked Time/ Clock that returns negative millis; clock skew on misconfigured VMs or containers where System.currentTimeMillis() is unreliable.
Related errors
- Topic cannot be null.
- Invalid partition: %d. Partition number should always be non
- Timestamp type must be provided to compute attributes for me
- Invalid message timestamp {}
- Invalid configuration value for 'acks': {acksString}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/57622e221e3b63b9.json.
Report an issue: GitHub.