{"record":{"id":"148c292867a143a4","repo":"apache/pulsar","slug":"runtime-cannot-be-altered","errorCode":null,"errorMessage":"Runtime cannot be altered","messagePattern":"Runtime cannot be altered","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java","lineNumber":1087,"sourceCode":"        if (newConfig.getRetainOrdering() != null && !newConfig.getRetainOrdering()\n                .equals(existingConfig.getRetainOrdering())) {\n            throw new IllegalArgumentException(\"Retain Ordering cannot be altered\");\n        }\n        if (newConfig.getRetainKeyOrdering() != null && !newConfig.getRetainKeyOrdering()\n                .equals(existingConfig.getRetainKeyOrdering())) {\n            throw new IllegalArgumentException(\"Retain Key Ordering cannot be altered\");\n        }\n        if (!StringUtils.isEmpty(newConfig.getOutput())) {\n            mergedConfig.setOutput(newConfig.getOutput());\n        }\n        if (newConfig.getUserConfig() != null) {\n            mergedConfig.setUserConfig(newConfig.getUserConfig());\n        }\n        if (newConfig.getSecrets() != null) {\n            mergedConfig.setSecrets(newConfig.getSecrets());\n        }\n        if (newConfig.getRuntime() != null && !newConfig.getRuntime().equals(existingConfig.getRuntime())) {\n            throw new IllegalArgumentException(\"Runtime cannot be altered\");\n        }\n        @SuppressWarnings(\"deprecation\")\n        boolean autoAckChanged = newConfig.getAutoAck() != null\n                && !newConfig.getAutoAck().equals(existingConfig.getAutoAck());\n        if (autoAckChanged) {\n            throw new IllegalArgumentException(\"AutoAck cannot be altered\");\n        }\n        if (newConfig.getMaxMessageRetries() != null) {\n            mergedConfig.setMaxMessageRetries(newConfig.getMaxMessageRetries());\n        }\n        if (!StringUtils.isEmpty(newConfig.getDeadLetterTopic())) {\n            mergedConfig.setDeadLetterTopic(newConfig.getDeadLetterTopic());\n        }\n        if (!StringUtils.isEmpty(newConfig.getSubName()) && !newConfig.getSubName()\n                .equals(existingConfig.getSubName())) {\n            throw new IllegalArgumentException(\"Subscription Name cannot be altered\");\n        }\n        if (newConfig.getParallelism() != null) {","sourceCodeStart":1069,"sourceCodeEnd":1105,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/FunctionConfigUtils.java#L1069-L1105","documentation":"A function's runtime (JAVA, PYTHON, GO, etc.) is fixed at creation time. validateUpdate throws IllegalArgumentException if an update attempts to change it, since the worker's runtime machinery cannot be swapped in place for a running function.","triggerScenarios":"Calling updateFunction with a FunctionConfig whose getRuntime() is non-null and differs from existingConfig.getRuntime().","commonSituations":"Rewriting a Java function in Python and trying to update in place; update code that copies runtime from a different config object; tooling that sets runtime explicitly on every submit.","solutions":["Do not set runtime (or set it to the existing value) when updating.","Delete and re-create the function with the new runtime to switch languages.","Verify the code path building the update config isn't picking up a foreign runtime value."],"exampleFix":"// before\nupdate.setRuntime(FunctionConfig.Runtime.PYTHON); // existing is JAVA -> thrown\n// after\nadmin.functions().deleteFunction(tenant, namespace, name);\nadmin.functions().createFunction(newConfigWithPythonRuntime, pkgFile);","handlingStrategy":"validation","validationCode":"FunctionConfig existing = admin.functions().getFunction(tenant, namespace, fnName);\nif (update.getRuntime() != null && !update.getRuntime().equals(existing.getRuntime())) {\n    throw new IllegalStateException(\"Runtime is immutable; delete and re-create the function\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.functions().updateFunction(update, pkgFile);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Runtime cannot be altered\")) { /* fall back to delete+create */ }\n    else throw e;\n}","preventionTips":["Never set runtime on update configs.","To change language/runtime, delete and re-create the function.","Centralize config-building so runtime is only set at creation."],"tags":["pulsar-functions","config-update","runtime"],"backgroundTag":"immutable-config-field","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"}