{"record":{"id":"5d02a3dd8f888148","repo":"apache/pulsar","slug":"lag-duration-must-be-positive-maxlagms","errorCode":null,"errorMessage":"Lag duration must be positive [${maxLagMs}]","messagePattern":"Lag duration must be positive \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/WindowConfigUtils.java","lineNumber":69,"sourceCode":"\n        if (windowConfig.getSlidingIntervalCount() != null) {\n            if (windowConfig.getSlidingIntervalCount() <= 0) {\n                throw new IllegalArgumentException(\n                        \"Sliding interval must be positive [\" + windowConfig.getSlidingIntervalCount() + \"]\");\n            }\n        }\n\n        if (windowConfig.getSlidingIntervalDurationMs() != null) {\n            if (windowConfig.getSlidingIntervalDurationMs() <= 0) {\n                throw new IllegalArgumentException(\n                        \"Sliding interval must be positive [\" + windowConfig.getSlidingIntervalDurationMs() + \"]\");\n            }\n        }\n\n        if (windowConfig.getTimestampExtractorClassName() != null) {\n            if (windowConfig.getMaxLagMs() != null) {\n                if (windowConfig.getMaxLagMs() < 0) {\n                    throw new IllegalArgumentException(\n                            \"Lag duration must be positive [\" + windowConfig.getMaxLagMs() + \"]\");\n                }\n            }\n            if (windowConfig.getWatermarkEmitIntervalMs() != null) {\n                if (windowConfig.getWatermarkEmitIntervalMs() <= 0) {\n                    throw new IllegalArgumentException(\n                            \"Watermark interval must be positive [\" + windowConfig.getWatermarkEmitIntervalMs() + \"]\");\n                }\n            }\n        }\n    }\n\n    public static void inferMissingArguments(WindowConfig windowConfig) {\n        if (windowConfig.getWindowLengthDurationMs() != null && windowConfig.getSlidingIntervalDurationMs() == null) {\n            windowConfig.setSlidingIntervalDurationMs(windowConfig.getWindowLengthDurationMs());\n        }\n\n        if (windowConfig.getWindowLengthCount() != null && windowConfig.getSlidingIntervalCount() == null) {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/WindowConfigUtils.java#L51-L87","documentation":"WindowConfigUtils.validate() checks watermark/lag settings when a timestampExtractorClassName is configured. maxLagMs bounds how late events may arrive relative to the watermark; this IllegalArgumentException is thrown when maxLagMs is provided and is negative. (Zero is allowed here — the check is `< 0`, unlike other interval checks.)","triggerScenarios":"Calling WindowConfigUtils.validate(windowConfig) on a WindowConfig that sets timestampExtractorClassName and has maxLagMs < 0 (e.g. -1L).","commonSituations":"Using -1 as a sentinel for 'unbounded' or 'unset' lag in handwritten configs; computing the lag as a difference (current - event time) that went negative due to clock skew; copying a config template where the lag placeholder was negative.","solutions":["Set windowConfig.maxLagMs to a non-negative value (0 for no allowed lag, or a positive bound like 60000).","Remove maxLagMs (set to null) to use the default if you did not intend to bound lateness.","Guard the computed value: clamp with Math.max(0, computedLagMs) before building the config."],"exampleFix":"// before\nWindowConfig.builder().setTimestampExtractorClassName(MyExtractor.class.getName()).setMaxLagMs(-1).build();\n// after\nWindowConfig.builder().setTimestampExtractorClassName(MyExtractor.class.getName()).setMaxLagMs(60000).build();","handlingStrategy":"validation","validationCode":"if (cfg.getTimestampExtractorClassName() != null && cfg.getMaxLagMs() != null && cfg.getMaxLagMs() < 0) {\n    throw new IllegalArgumentException(\"maxLagMs must be >= 0, got \" + cfg.getMaxLagMs());\n}","typeGuard":null,"tryCatchPattern":"try {\n    WindowConfigUtils.validate(windowConfig);\n} catch (IllegalArgumentException e) {\n    throw new IllegalArgumentException(\"Fix maxLagMs: \" + e.getMessage(), e);\n}","preventionTips":["Clamp computed lag values with Math.max(0, value).","Don't use negative sentinels for 'unbounded' lag; omit the field instead.","When enabling a timestamp extractor, review all related fields (maxLagMs, watermarkEmitIntervalMs) together."],"tags":["pulsar-functions","configuration","windowing","watermarks"],"backgroundTag":"config-validation-failed","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}