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
- Use the update endpoint (PUT .../sinks/{tenant}/{ns}/{name}) instead of create if you intend to replace the existing sink.
- Delete the existing sink first: pulsar-admin sinks delete tenant/ns/name, then create.
- Choose a unique sink name for a genuinely new component; remember function/source/sink names share one namespace.
- 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
- Make deployment scripts idempotent: check-then-update instead of unconditional create
- Use unique, environment-suffixed component names to avoid cross-team collisions
- Remember function/source/sink names share a namespace - check all three when picking a name
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
- Tenant is not provided
- Namespace is not provided
- Sink name is not provided
- Sink config is not provided
- Namespace does not exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/2f90bde2255a1de3.
Report an issue: GitHub.