apache/pulsar · error · IllegalArgumentException

Namespaces differ

Error message

Namespaces differ

What it means

validateUpdate requires the namespace of the source to remain unchanged across updates. Sources are addressed by tenant/namespace/name; changing the namespace would repoint the source's identity and topics, so it is rejected.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SourceConfigUtils.java:386

            }
        }

        return new ExtractedSourceDetails(sourceClassName, typeArg.asErasure().getTypeName());
    }

    @SneakyThrows
    public static SourceConfig clone(SourceConfig sourceConfig) {
        return ObjectMapperFactory.getMapper().reader().readValue(
                ObjectMapperFactory.getMapper().writer().writeValueAsBytes(sourceConfig), SourceConfig.class);
    }

    public static SourceConfig validateUpdate(SourceConfig existingConfig, SourceConfig newConfig) {
        SourceConfig 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("Function Names differ");
        }
        if (!StringUtils.isEmpty(newConfig.getClassName())) {
            mergedConfig.setClassName(newConfig.getClassName());
        }
        if (!StringUtils.isEmpty(newConfig.getTopicName())) {
            mergedConfig.setTopicName(newConfig.getTopicName());
        }
        if (!StringUtils.isEmpty(newConfig.getSerdeClassName())) {
            mergedConfig.setSerdeClassName(newConfig.getSerdeClassName());
        }
        if (!StringUtils.isEmpty(newConfig.getSchemaType())) {
            mergedConfig.setSchemaType(newConfig.getSchemaType());
        }
        if (newConfig.getConfigs() != null) {
            mergedConfig.setConfigs(newConfig.getConfigs());

View on GitHub (pinned to 820761864e)

Solutions

  1. Resubmit the update with namespace identical to the existing source's namespace
  2. Call the update API on the correct tenant/namespace where the source lives
  3. To relocate the source, delete and recreate it in the target namespace

Example fix

// before
{"tenant":"t1","namespace":"ns2","name":"src1", ...}
// after
{"tenant":"t1","namespace":"ns1","name":"src1", ...}
Defensive patterns

Strategy: validation

Validate before calling

if (!Objects.equals(existing.getNamespace(), update.getNamespace())) {
    throw new IllegalArgumentException("namespace is immutable on update");
}

Try / catch

try { SourceConfigUtils.validateUpdate(existing, update); } catch (IllegalArgumentException e) { if (e.getMessage().equals("Namespaces differ")) { update.setNamespace(existing.getNamespace()); } else { throw e; } }

Prevention

When it happens

Trigger: validateUpdate is given a newConfig whose getNamespace() differs from existingConfig.getNamespace(), e.g. an update request submitted under a different namespace than where the source was created.

Common situations: Submitting the update against the wrong namespace endpoint while the config body names the original namespace (or vice versa); renaming/refactoring namespaces in templates; moving sources during environment migration.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/e0a80ab1a23bf2a0. Report an issue: GitHub.