{"record":{"id":"ddb28a2a5ce20b85","repo":"apache/pulsar","slug":"windows-function-not-support-delivery-semantics","errorCode":null,"errorMessage":"Windows Function not support  delivery semantics.","messagePattern":"Windows Function not support  delivery semantics\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":323,"sourceCode":"            RetryDetails retryDetails = functionDetails.setRetryDetails();\n            retryDetails.setMaxMessageRetries(functionConfig.getMaxMessageRetries());\n            if (isNotEmpty(functionConfig.getDeadLetterTopic())) {\n                retryDetails.setDeadLetterTopic(functionConfig.getDeadLetterTopic());\n            }\n        }\n\n        Map<String, Object> configs = new HashMap<>();\n        if (functionConfig.getUserConfig() != null) {\n            configs.putAll(functionConfig.getUserConfig());\n        }\n\n        // windowing related\n        WindowConfig windowConfig = functionConfig.getWindowConfig();\n        if (windowConfig != null) {\n            // Windows Function not support MANUAL and EFFECTIVELY_ONCE.\n            if (functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE\n                    || functionConfig.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.MANUAL) {\n                throw new IllegalArgumentException(\n                        \"Windows Function not support \"\n                                + functionConfig.getProcessingGuarantees() + \" delivery semantics.\");\n            } else {\n                // Override functionConfig.getProcessingGuarantees to MANUAL, and set windowsFunction is guarantees\n                windowConfig.setProcessingGuarantees(WindowConfig.ProcessingGuarantees\n                        .valueOf(functionDetails.getProcessingGuarantees().name()));\n                functionDetails.setProcessingGuarantees(ProcessingGuarantees.MANUAL);\n            }\n            windowConfig.setActualWindowFunctionClassName(extractedDetails.getFunctionClassName());\n            configs.put(WindowConfig.WINDOW_CONFIG_KEY, windowConfig);\n            // set class name to window function executor\n            functionDetails.setClassName(\"org.apache.pulsar.functions.windowing.WindowFunctionExecutor\");\n        } else {\n            if (extractedDetails.getFunctionClassName() != null) {\n                functionDetails.setClassName(extractedDetails.getFunctionClassName());\n            }\n        }\n        if (!configs.isEmpty()) {","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L305-L341","documentation":"Pulsar Functions windowing only supports certain delivery semantics. When a WindowConfig is present, convert() rejects EFFECTIVELY_ONCE and MANUAL processing guarantees with this IllegalArgumentException ('Windows Function not support <X> delivery semantics'), because the windowing implementation cannot provide them.","triggerScenarios":"Submitting a function whose FunctionConfig has both a non-null windowConfig and processingGuarantees set to EFFECTIVELY_ONCE (or MANUAL) — e.g. a windowed function created with --processing-guarantees EFFECTIVELY_ONCE via the CLI or REST API.","commonSituations":"Developers adding at-least-once/effectively-once guarantees to an existing windowed function assuming all guarantees are supported; copy-pasted function configs combining windowing with effectively-once; migration scripts setting guarantees globally for all functions including windowed ones.","solutions":["Remove the windowConfig if you require EFFECTIVELY_ONCE processing guarantees","Set processingGuarantees to ATLEAST_ONCE or ATMOST_ONCE for windowed functions","If MANUAL was set implicitly, explicitly set a supported guarantee before submitting the windowed function","Use non-windowed function logic plus external deduplication if exactly-once semantics are mandatory"],"exampleFix":"// before\ncfg.setWindowConfig(new WindowConfig());\ncfg.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE); // throws\n// after\ncfg.setWindowConfig(new WindowConfig());\ncfg.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE); // supported for windowing","handlingStrategy":"validation","validationCode":"// Pre-validate windowing + guarantee combination\nif (cfg.getWindowConfig() != null\n    && (cfg.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.EFFECTIVELY_ONCE\n        || cfg.getProcessingGuarantees() == FunctionConfig.ProcessingGuarantees.MANUAL)) {\n  throw new IllegalArgumentException(\"Windowed functions require ATLEAST_ONCE or ATMOST_ONCE\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  FunctionDetails d = FunctionConfigUtils.convert(cfg, pkg);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Windows Function not support\")) {\n    cfg.setProcessingGuarantees(FunctionConfig.ProcessingGuarantees.ATLEAST_ONCE);\n    d = FunctionConfigUtils.convert(cfg, pkg); // retry with supported guarantee\n  } else {\n    throw e;\n  }\n}","preventionTips":["Remember windowing only supports ATLEAST_ONCE and ATMOST_ONCE","Never blanket-apply EFFECTIVELY_ONCE across all function configs in migration scripts","Validate windowed function configs before CLI submission","Document the guarantee limitation for users of your function platform"],"tags":["pulsar-functions","windowing","processing-guarantees","configuration"],"backgroundTag":"unsupported-processing-guarantee","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}