apache/pulsar · error · RestException

%s %s already exists

Error message

%s %s already exists

What it means

Thrown when FunctionMetaDataManager.containsFunction reports a source with the same name already exists in the tenant/namespace. The worker rejects the registration with HTTP 400 BAD_REQUEST because Pulsar treats component names as unique per namespace — you must update, not register.

Source

Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java:145

        } catch (PulsarAdminException.NotFoundException e) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)

                    .attr("tenant3", tenant).log("/ / Tenant does not exist");
            throw new RestException(Response.Status.BAD_REQUEST, "Tenant does not exist");
        } catch (PulsarAdminException e) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)

                    .exception(e).log("/ / Issues getting tenant data");
            throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());
        }

        FunctionMetaDataManager functionMetaDataManager = worker().getFunctionMetaDataManager();

        if (functionMetaDataManager.containsFunction(tenant, namespace, sourceName)) {
            log.error().attr("componentType", ComponentTypeUtils.toString(componentType)).attr("tenant", tenant)

                    .attr("namespace", namespace).attr("componentName", sourceName).log("/ / already exists");
            throw new RestException(Response.Status.BAD_REQUEST,
                    String.format("%s %s already exists", ComponentTypeUtils.toString(componentType), sourceName));
        }

        FunctionDetails functionDetails = null;
        boolean isPkgUrlProvided = isNotBlank(sourcePkgUrl);
        File componentPackageFile = null;
        try {

            // validate parameters
            try {
                if (isPkgUrlProvided) {
                    componentPackageFile = getPackageFile(componentType, sourcePkgUrl);
                    functionDetails = validateUpdateRequestParams(tenant, namespace, sourceName,
                            sourceConfig, componentPackageFile);
                } else {
                    if (uploadedInputStream != null) {
                        componentPackageFile = WorkerUtils.dumpToTmpFile(uploadedInputStream);
                    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Use the update endpoint/trigger instead of create: pulsar-admin sources update ...
  2. Delete the existing source first: pulsar-admin sources delete --tenant <t> --namespace <ns> --name <name>, then create
  3. List existing sources to check the collision: pulsar-admin sources list --tenant <t> --namespace <ns>
  4. Pick a unique sourceName for the new source

Example fix

// before
pulsar-admin sources create --tenant public --namespace default --name my-source ... // -> 400 my-source already exists
// after
pulsar-admin sources update --tenant public --namespace default --name my-source --sourceConfigFile my-source.yaml
Defensive patterns

Strategy: validation

Validate before calling

try (PulsarAdmin admin = PulsarAdminClient.builder().serviceHttpUrl(adminUrl).build()) {
    boolean exists = admin.sources().listSources(tenant, namespace)
            .stream().anyMatch(s -> s.getName().equals(sourceName));
    if (exists) {
        admin.sources().updateSource(sourceConfig, pkgUrl, inputStream); // update instead of create
    } else {
        admin.sources().createSource(sourceConfig, pkgUrl, inputStream);
    }
}

Type guard

boolean sourceExists(java.util.List<org.apache.pulsar.common.functions.SourceConfig> configs, String name) {
    return configs != null && configs.stream().anyMatch(c -> name.equals(c.getName()));
}

Try / catch

try {
    sources.createSource(sourceConfig, pkgUrl, inputStream);
} catch (PulsarAdminException e) {
    if (e.getMessage() != null && e.getMessage().endsWith("already exists")) {
        sources.updateSource(sourceConfig, pkgUrl, inputStream); // idempotent upsert
    } else { throw e; }
}

Prevention

When it happens

Trigger: POSTing a registration for a source whose (tenant, namespace, sourceName) triple already has a registered source; re-running a create script without deleting the old source; accidental name collision between sources and functions in the same namespace.

Common situations: CI/CD re-deploying a source with create instead of update; failed previous deployment left the source registered; multiple teams reusing the same source name; copy-pasted configs with an unchanged sourceName.

Related errors


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