{"id":"ea42a05e9f132753","repo":"apache/kafka","slug":"the-target-time-for-partition-is-the-target","errorCode":null,"errorMessage":"The target time for partition {} is {}. The target time cannot be negative.","messagePattern":"The target time for partition (.+?) is (.+?)\\. The target time cannot be negative\\.","errorType":"validation","errorClass":"java.lang.IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java","lineNumber":1413,"sourceCode":"    }\n\n    @Override\n    public Map<TopicPartition, OffsetAndTimestamp> offsetsForTimes(Map<TopicPartition, Long> timestampsToSearch) {\n        return offsetsForTimes(timestampsToSearch, defaultApiTimeoutMs);\n    }\n\n    @Override\n    public Map<TopicPartition, OffsetAndTimestamp> offsetsForTimes(Map<TopicPartition, Long> timestampsToSearch, Duration timeout) {\n        acquireAndEnsureOpen();\n        try {\n            // Keeping same argument validation error thrown by the current consumer implementation\n            // to avoid API level changes.\n            requireNonNull(timestampsToSearch, \"Timestamps to search cannot be null\");\n            for (Map.Entry<TopicPartition, Long> entry : timestampsToSearch.entrySet()) {\n                // Exclude the earliest and latest offset here so the timestamp in the returned\n                // OffsetAndTimestamp is always positive.\n                if (entry.getValue() < 0)\n                    throw new IllegalArgumentException(\"The target time for partition \" + entry.getKey() + \" is \" +\n                        entry.getValue() + \". The target time cannot be negative.\");\n            }\n\n            if (timestampsToSearch.isEmpty()) {\n                return Collections.emptyMap();\n            }\n            ListOffsetsEvent listOffsetsEvent = new ListOffsetsEvent(\n                    timestampsToSearch,\n                    calculateDeadlineMs(time, timeout),\n                    true);\n\n            // If timeout is set to zero return empty immediately; otherwise try to get the results\n            // and throw timeout exception if it cannot complete in time.\n            if (timeout.toMillis() == 0L) {\n                applicationEventHandler.add(listOffsetsEvent);\n                return listOffsetsEvent.emptyResults();\n            }\n","sourceCodeStart":1395,"sourceCodeEnd":1431,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/AsyncKafkaConsumer.java#L1395-L1431","documentation":"IllegalArgumentException from offsetsForTimes when any value in the timestampsToSearch map is negative. The broker's ListOffsets request interprets special non-negative sentinels (earliest=-2, latest=-1 internally), but the public consumer API exposes those via beginningOffsets/endOffsets; user-supplied timestamps must be wall-clock milliseconds >= 0. The message names the offending partition and value to aid diagnosis.","triggerScenarios":"Calling consumer.offsetsForTimes(Map<TopicPartition, Long>) where any Long value is < 0, including passing ListOffsetsRequest.EARLIEST_TIMESTAMP (-2) / LATEST_TIMESTAMP (-1) constants (which are internal sentinels), or using -1 as a 'not found' placeholder, or computing timestamp = someDate.getTime() from a null/epoch Date that yields 0 or negative.","commonSituations":"Copy-paste from internal broker code that uses LATEST_TIMESTAMP/EARLIEST_TIMESTAMP constants; deriving search timestamps from event headers that default to -1; arithmetic like System.currentTimeMillis() - retentionMs that underflows due to misconfigured retention; clock-skew scenarios producing negative deltas.","solutions":["Replace negative sentinel values with real epoch-millis timestamps or use beginningOffsets()/endOffsets() for earliest/latest semantics.","Sanitize the map before calling: timestampsToSearch.values().removeIf(v -> v < 0).","Validate the source of timestamps; default missing/unknown entries to System.currentTimeMillis() or 0 (start-of-time)."],"exampleFix":"// before\nMap<TopicPartition, Long> q = Map.of(tp, -1L);\nconsumer.offsetsForTimes(q); // throws\n\n// after\nMap<TopicPartition, Long> q = Map.of(tp, System.currentTimeMillis() - 3600_000L);\nconsumer.offsetsForTimes(q);","handlingStrategy":"validation","validationCode":"Map<TopicPartition, Long> safe = new HashMap<>();\ntimestampsToSearch.forEach((tp, ts) -> {\n    if (ts == null || ts < 0L) {\n        throw new IllegalArgumentException(\"timestamp for \" + tp + \" must be >= 0; use -1 semantics via ListOffsetsRequest only inside the client\");\n    }\n    safe.put(tp, ts);\n});\nconsumer.offsetsForTimes(safe, timeout);","typeGuard":"boolean allTimestampsNonNegative(Map<TopicPartition, Long> ts) {\n    return ts != null && ts.values().stream().allMatch(v -> v != null && v >= 0L);\n}","tryCatchPattern":null,"preventionTips":["offsetsForTimes rejects any negative timestamp with IllegalArgumentException; sanitize the whole map before the call.","Use ListOffsetsRequest.EARLIEST/LATEST constants only at the protocol layer — the public API expects wall-clock millis >= 0.","Guard against null values in the map, not just null map; both will NPE or misbehave downstream."],"tags":["kafka","consumer","offsets","validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}