apache/pulsar · error · RestException

%s %s already exists

Error message

%s %s already exists

What it means

registerSink checks FunctionMetaDataManager.containsFunction(tenant, namespace, sinkName) and throws a 400 Bad Request RestException when a component of that type already exists at the same coordinates, with message formatted as "<ComponentType> <sinkName> already exists" (e.g. "Sink my-sink already exists"). Sink names must be unique per tenant/namespace among registered functions/sources/sinks.

Source

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

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

                    .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", sinkName)

                    .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, sinkName)) {
            log.error().attr("componentType", ComponentTypeUtils.toString(componentType)).attr("tenant", tenant)

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

        FunctionDetails functionDetails;
        File componentPackageFile = null;
        try {

            // validate parameters
            try {
                if (isNotBlank(sinkPkgUrl)) {
                    componentPackageFile = getPackageFile(componentType, sinkPkgUrl);
                    functionDetails = validateUpdateRequestParams(tenant, namespace, sinkName,
                            sinkConfig, componentPackageFile);
                } else {
                    if (uploadedInputStream != null) {
                        componentPackageFile = WorkerUtils.dumpToTmpFile(uploadedInputStream);
                    }
                    functionDetails = validateUpdateRequestParams(tenant, namespace, sinkName,

View on GitHub (pinned to 820761864e)

Solutions

  1. Use the update endpoint (PUT .../sinks/{tenant}/{ns}/{name}) instead of create if you intend to replace the existing sink.
  2. Delete the existing sink first: pulsar-admin sinks delete tenant/ns/name, then create.
  3. Choose a unique sink name for a genuinely new component; remember function/source/sink names share one namespace.
  4. Check existing components with pulsar-admin sinks list tenant/ns before deploying.

Example fix

// before: re-creating an existing sink
curl -X POST .../sinks/t/ns/my-sink  # 400 Sink my-sink already exists
// after: update instead of create
curl -X PUT .../sinks/t/ns/my-sink -H "Content-Type: application/json" -d @sink-config.json
Defensive patterns

Strategy: validation

Validate before calling

if (admin.sinks().getSink(tenant, namespace, sinkName) != null) {
    throw new IllegalStateException("Sink " + sinkName + " already exists; use update or delete first");
}

Try / catch

try {
    sinks.registerSink(tenant, ns, name, cfg, null, null, null, authParams);
} catch (RestException e) {
    if (e.getResponse().getStatus() == 400 && e.getMessage() != null && e.getMessage().endsWith("already exists")) {
        // switch to the update endpoint or delete/recreate
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling the sink creation endpoint (PUT without update semantics / POST create) when a function, source, or sink with the same tenant/namespace/sinkName is already registered in the workers' metadata manager.

Common situations: Re-running an idempotency-unsafe deployment script; name collision between a function and a sink sharing a name; CI pipelines retried after a partially successful deploy; teams unaware names are shared across component types.

Related errors


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