apache/pulsar · error · IllegalArgumentException

Function Names differ

Error message

Function Names differ

What it means

Update-compatibility check in SourceConfigUtils.validateUpdate: the source's function name differs between the existing and new configuration (the tenant/namespace identity checks precede it), and renaming is not permitted via update; the changed function name is the faulty input.

Source

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

        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());
        }
        if (newConfig.getSecrets() != null) {
            mergedConfig.setSecrets(newConfig.getSecrets());

View on GitHub (pinned to 820761864e)

Solutions

  1. Keep the name identical when updating; delete+create to rename

Example fix

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

Strategy: validation

Validate before calling

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

Try / catch

try { SourceConfigUtils.validateUpdate(existing, update); } catch (IllegalArgumentException e) { if (e.getMessage().equals("Function Names differ")) { update.setName(existing.getName()); } else { throw e; } }

Prevention

When it happens

Trigger: validateUpdate receives a newConfig whose getName() differs from the existing config's name — e.g. an update payload for one source accidentally applied to another, or the name edited in a config template.

Common situations: Copy-pasting a source config, editing the name, then submitting it as an update to the original source; CI tooling that derives the name from a branch/feature flag; off-by-one in scripts iterating source configs.

Related errors


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