{"record":{"id":"027388860e438c6e","repo":"apache/pulsar","slug":"e-getmessage-027388","errorCode":null,"errorMessage":"{e.getMessage()}","messagePattern":"\\{e\\.getMessage\\(\\)\\}","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"error","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java","lineNumber":323,"sourceCode":"            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sinkName)\n\n                    .attr(\"componentType\", ComponentTypeUtils.toString(componentType)).log(\"/ / is not a\");\n            throw new RestException(Response.Status.NOT_FOUND,\n                    String.format(\"%s %s doesn't exist\", ComponentTypeUtils.toString(componentType), sinkName));\n        }\n\n\n        SinkConfig existingSinkConfig = SinkConfigUtils.convertFromDetails(existingComponent.getFunctionDetails());\n        // The rest end points take precedence over whatever is there in functionconfig\n        sinkConfig.setTenant(tenant);\n        sinkConfig.setNamespace(namespace);\n        sinkConfig.setName(sinkName);\n\n        SinkConfig mergedConfig;\n        try {\n            mergedConfig = SinkConfigUtils.validateUpdate(existingSinkConfig, sinkConfig);\n        } catch (Exception e) {\n            throw new RestException(Response.Status.BAD_REQUEST, e.getMessage());\n        }\n\n        if (existingSinkConfig.equals(mergedConfig) && isBlank(sinkPkgUrl) && uploadedInputStream == null\n                && (updateOptions == null || !updateOptions.isUpdateAuthData())) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sinkName)\n\n                    .log(\"/ / Update contains no changes\");\n            throw new RestException(Response.Status.BAD_REQUEST, \"Update contains no change\");\n        }\n\n        FunctionDetails functionDetails;\n        File componentPackageFile = null;\n        try {\n\n            // validate parameters\n            try {\n                componentPackageFile = getPackageFile(\n                        componentType,","sourceCodeStart":305,"sourceCodeEnd":341,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java#L305-L341","documentation":"SinkConfigUtils.validateUpdate compares the existing sink config with the submitted update and throws when the update is invalid (e.g. disallowed field change). SinksImpl catches any exception and rethrows it as HTTP 400 BAD_REQUEST with the underlying message, so the text you see is the validation failure from SinkConfigUtils.","triggerScenarios":"PUT /admin/v3/sinks/{tenant}/{namespace}/{name} with a SinkConfig that attempts an illegal update, such as changing immutable fields (subscription type/position, processing guarantees, tenant/namespace/name mismatches) relative to the existing sink.","commonSituations":"Changing subscriptionName or subscriptionPosition on an existing sink; trying to rename a sink via update; CI pipelines that regenerate the full config from scratch and drift immutable fields.","solutions":["Read the returned message to identify which config field failed validation.","Resend only fields that SinkConfigUtils allows to change; keep immutable fields identical to the existing config.","Fetch the current config (GET sink) and diff it against your payload before submitting.","If a fundamentally different config is needed, delete and recreate the sink."],"exampleFix":"// before: changing subscriptionPosition in an update\nsinkConfig.setSubscriptionPosition(SubscriptionInitialPosition.Earliest);\n// after: leave immutable fields untouched\n// sinkConfig keeps existingSinkConfig.getSubscriptionPosition()","handlingStrategy":"validation","validationCode":"SinkConfig current = admin.sinks().getSinkConfig(tenant, ns, name);\nif (!Objects.equals(current.getSubscriptionName(), cfg.getSubscriptionName())) {\n    throw new IllegalArgumentException(\"subscriptionName is immutable in update\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.sinks().updateSink(tenant, ns, name, cfg, null, null);\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 400) log.error(\"Validation rejected: \" + e.getMessage());\n}","preventionTips":["Fetch the current config and diff before every update.","Keep a template that only mutates allowed fields.","Never rename a sink via update; recreate instead."],"tags":["rest-api","bad-request","pulsar-functions","config-validation"],"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-14T00:17:10.932Z"}