{"record":{"id":"800b82bfbad8871b","repo":"apache/druid","slug":"seekablestreamsupervisorioconfig-does-not-support","errorCode":null,"errorMessage":"SeekableStreamSupervisorIOConfig does not support both properties lateMessageRejectionStartDateTime and lateMessageRejectionPeriod.","messagePattern":"SeekableStreamSupervisorIOConfig does not support both properties lateMessageRejectionStartDateTime and lateMessageRejectionPeriod\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisorIOConfig.java","lineNumber":139,"sourceCode":"    this.stopTaskCount = stopTaskCount;\n    this.taskDuration = defaultDuration(taskDuration, \"PT1H\");\n    this.startDelay = defaultDuration(startDelay, \"PT5S\");\n    this.period = defaultDuration(period, \"PT30S\");\n    this.useEarliestSequenceNumber = useEarliestSequenceNumber != null ? useEarliestSequenceNumber : false;\n    this.completionTimeout = defaultDuration(completionTimeout, \"PT30M\");\n    this.lateMessageRejectionPeriod = lateMessageRejectionPeriod == null\n                                      ? Optional.absent()\n                                      : Optional.of(lateMessageRejectionPeriod.toStandardDuration());\n    this.lateMessageRejectionStartDateTime = lateMessageRejectionStartDateTime == null\n                                      ? Optional.absent()\n                                      : Optional.of(lateMessageRejectionStartDateTime);\n    this.earlyMessageRejectionPeriod = earlyMessageRejectionPeriod == null\n                                       ? Optional.absent()\n                                       : Optional.of(earlyMessageRejectionPeriod.toStandardDuration());\n\n    if (this.lateMessageRejectionPeriod.isPresent()\n                && this.lateMessageRejectionStartDateTime.isPresent()) {\n      throw new IAE(\"SeekableStreamSupervisorIOConfig does not support \"\n                + \"both properties lateMessageRejectionStartDateTime \"\n          + \"and lateMessageRejectionPeriod.\");\n    }\n\n    this.idleConfig = idleConfig;\n    this.serverPriorityToReplicas = serverPriorityToReplicas;\n    this.boundedStreamConfig = boundedStreamConfig;\n\n    if (this.serverPriorityToReplicas != null) {\n      int serverPriorityReplicas = 0;\n      for (Map.Entry<Integer, Integer> entry : this.serverPriorityToReplicas.entrySet()) {\n        final Integer serverReplica = entry.getValue();\n\n        if (serverReplica == null || serverReplica < 0) {\n          throw InvalidInput.exception(\n              \"Found invalid server replica[%d] for priority[%d] in serverPriorityToReplicas[%s]. Replicas must be >= 0.\",\n              serverReplica, entry.getKey(), serverPriorityToReplicas\n          );","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/SeekableStreamSupervisorIOConfig.java#L121-L157","documentation":"SeekableStreamSupervisorIOConfig allows limiting late messages either by a relative period (lateMessageRejectionPeriod) or by an absolute datetime (lateMessageRejectionStartDateTime), but not both. The constructor validates this mutual exclusivity and throws IAE when both are set in the supervisor spec.","triggerScenarios":"Submitting/creating a supervisor spec whose ioConfig contains both lateMessageRejectionPeriod and lateMessageRejectionStartDateTime non-null.","commonSituations":"Copy-pasting spec fragments that each carried one of the two properties; merging old and new ingestion specs during migration; templated spec generation accidentally filling both fields.","solutions":["Remove lateMessageRejectionStartDateTime and keep only lateMessageRejectionPeriod (relative window), or vice versa.","Use lateMessageRejectionStartDateTime for a one-time cutoff (e.g. after a backfill) and lateMessageRejectionPeriod for an ongoing rolling window.","If generating specs from templates, ensure only one of the two keys is ever emitted."],"exampleFix":"// before\n\"ioConfig\": {\n  \"lateMessageRejectionPeriod\": \"P7D\",\n  \"lateMessageRejectionStartDateTime\": \"2024-01-01T00:00:00Z\"\n}\n// after: keep only one\n\"ioConfig\": {\n  \"lateMessageRejectionPeriod\": \"P7D\"\n}","handlingStrategy":"validation","validationCode":"if (ioConfig.lateMessageRejectionPeriod != null && ioConfig.lateMessageRejectionStartDateTime != null) {\n    throw new IllegalArgumentException(\"Set only one of lateMessageRejectionPeriod / lateMessageRejectionStartDateTime\");\n}","typeGuard":null,"tryCatchPattern":"try { submitSupervisorSpec(spec); } catch (IAE e) { if (e.getMessage().contains(\"lateMessageRejection\")) { stripConflictingProperty(spec); } }","preventionTips":["Pick period vs startDateTime per use case and document it","Validate spec templates to emit only one key","Lint specs before submission"],"tags":["druid","supervisor","config","validation"],"backgroundTag":"mutually-exclusive-options","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}