apache/pulsar · error · IllegalArgumentException
Namespaces differ
Error message
Namespaces differ
What it means
Update-compatibility check in SinkConfigUtils.validateUpdate: the existing and new sink configurations live in different namespaces, which would relocate the sink; sink updates must preserve tenant/namespace/name identity, so the differing namespace fields are rejected.
Source
Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java:616
retval.addAll(sinkConfig.getInputSpecs().keySet());
}
return retval;
}
@SneakyThrows
public static SinkConfig clone(SinkConfig sinkConfig) {
return ObjectMapperFactory.getMapper().reader().readValue(
ObjectMapperFactory.getMapper().writer().writeValueAsBytes(sinkConfig), SinkConfig.class);
}
public static SinkConfig validateUpdate(SinkConfig existingConfig, SinkConfig newConfig) {
SinkConfig mergedConfig = clone(existingConfig);
if (!existingConfig.getTenant().equals(newConfig.getTenant())) {
throw new IllegalArgumentException("Tenants differ");
}
if (!existingConfig.getNamespace().equals(newConfig.getNamespace())) {
throw new IllegalArgumentException("Namespaces differ");
}
if (!existingConfig.getName().equals(newConfig.getName())) {
throw new IllegalArgumentException("Sink Names differ");
}
if (!StringUtils.isEmpty(newConfig.getClassName())) {
mergedConfig.setClassName(newConfig.getClassName());
}
if (!StringUtils.isEmpty(newConfig.getSourceSubscriptionName()) && !newConfig.getSourceSubscriptionName()
.equals(existingConfig.getSourceSubscriptionName())) {
throw new IllegalArgumentException("Subscription Name cannot be altered");
}
if (newConfig.getInputSpecs() == null) {
newConfig.setInputSpecs(new HashMap<>());
}
if (mergedConfig.getInputSpecs() == null) {
mergedConfig.setInputSpecs(new HashMap<>());View on GitHub (pinned to 820761864e)
Solutions
- Keep the namespace unchanged; recreate the sink elsewhere if needed
Example fix
// before
newConfig.setNamespace("ns2");
SinkConfig merged = SinkConfigUtils.validateUpdate(existing, newConfig);
// after
newConfig.setNamespace(existing.getNamespace());
SinkConfig merged = SinkConfigUtils.validateUpdate(existing, newConfig); Defensive patterns
Strategy: validation
Validate before calling
if (!existing.getNamespace().equals(newConfig.getNamespace())) {
throw new IllegalStateException("Update cannot change namespace; delete+create instead");
} Try / catch
try {
admin.sinks().updateSink(tenant, ns, name, newConfig);
} catch (IllegalArgumentException e) {
if (e.getMessage() != null && e.getMessage().equals("Namespaces differ")) {
// recreate sink in target namespace via createSink
} else { throw e; }
} Prevention
- Clone existing config and mutate only allowed fields for updates
- Take namespace from the REST path, not the request body
When it happens
Trigger: Calling validateUpdate with a newConfig whose getNamespace() differs from existingConfig.getNamespace().
Common situations: Copying a sink config template across namespaces; admin tooling that rebuilds config from request body where namespace field was changed; trying to 'move' a sink via update.
Related errors
- Tenants differ
- Only one of serdeClassName or schemaType should be set
- When effectively once processing guarantee is specified, ret
- Only one of retain ordering or retain key ordering can be se
- %s Package is not provided
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/469855f5b6b35f79.
Report an issue: GitHub.