{"record":{"id":"b281656cd42e5e22","repo":"apache/pulsar","slug":"e-getmessage-b28165","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/SourcesImpl.java","lineNumber":316,"sourceCode":"        if (!InstanceUtils.calculateSubjectType(existingComponent.getFunctionDetails()).equals(componentType)) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sourceName)\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), sourceName));\n        }\n\n        SourceConfig existingSourceConfig =\n                SourceConfigUtils.convertFromDetails(existingComponent.getFunctionDetails());\n        // The rest end points take precedence over whatever is there in functionconfig\n        sourceConfig.setTenant(tenant);\n        sourceConfig.setNamespace(namespace);\n        sourceConfig.setName(sourceName);\n        SourceConfig mergedConfig;\n        try {\n            mergedConfig = SourceConfigUtils.validateUpdate(existingSourceConfig, sourceConfig);\n        } catch (Exception e) {\n            throw new RestException(Response.Status.BAD_REQUEST, e.getMessage());\n        }\n\n        if (existingSourceConfig.equals(mergedConfig) && isBlank(sourcePkgUrl) && uploadedInputStream == null\n            && (updateOptions == null || !updateOptions.isUpdateAuthData())) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", sourceName)\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":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java#L298-L334","documentation":"Thrown by SourcesImpl.updateSource when SourceConfigUtils.validateUpdate rejects the merge of the submitted SourceConfig with the existing one. validateUpdate enforces immutability rules (tenant/namespace/name/class cannot change) and validates the new config; any exception it throws is re-wrapped as a 400 BAD_REQUEST RestException carrying the underlying validation message.","triggerScenarios":"Calling PUT /admin/v3/sources/{tenant}/{namespace}/{sourceName} (or WorkerUtils-issued updateSource) with a SourceConfig that fails SourceConfigUtils.validateUpdate: changing an immutable field (tenant, namespace, name, className), supplying an invalid/missing typeName, or a config that does not deserialize/validate.","commonSituations":" Renaming a connector's className in the update payload; sending a config serialized with a mismatched schema or bad JSON; submitting an update that accidentally alters the source's identity fields; upgrading connector config where a previously optional field is now validated strictly.","solutions":["Fix the field named in e.getMessage() in the submitted SourceConfig (restore immutable fields tenant/namespace/name/className to their existing values)","Fetch the current config first via GET and change only allowed fields, letting validateUpdate merge them","Validate the config locally with SourceConfigUtils.validateUpdate(existingConfig, newConfig) before calling the update API","If the message indicates serialization problems, ensure the payload is valid SourceConfig JSON with correct types"],"exampleFix":"// before: update payload changes className\nSourceConfig cfg = getSourceConfig(existing);\ncfg.setClassName(\"org.example.NewSource\"); // rejected\n// after: keep className, update only mutable fields\ncfg.setClassName(existing.getClassName());\ncfg.setProcessingGuarantees(ProcessingGuarantees.EFFECTIVELY_ONCE);","handlingStrategy":"validation","validationCode":"SourceConfig existing = admin.sources().getSourceConfig(tenant, ns, name);\ntry {\n    SourceConfigUtils.validateUpdate(existing, proposed);\n} catch (Exception e) {\n    throw new IllegalArgumentException(\"Invalid source update: \" + e.getMessage(), e);\n}\nadmin.sources().updateSource(tenant, ns, name, proposed);","typeGuard":null,"tryCatchPattern":"try {\n    admin.sources().updateSource(tenant, ns, name, cfg);\n} catch (PulsarAdminException e) {\n    if (e.getStatusCode() == 400) {\n        log.error(\"Source update rejected: {}\", e.getMessage());\n    } else { throw e; }\n}","preventionTips":["GET the existing config and modify only mutable fields before PUT","Never send tenant/namespace/name/className changes in an update payload","Dry-run validateUpdate or SourceConfigUtils.validate locally before calling the API"],"tags":["rest-api","validation","pulsar-functions","bad-request"],"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"}