apache/pulsar · error · RestException
Sink config is not provided
Error message
Sink config is not provided
What it means
registerSink in SinksImpl throws a 400 Bad Request RestException when the submitted SinkConfig is null. The config carries the sink's runtime settings (className, inputs, topics pattern, etc.) needed to derive FunctionDetails. This is the last of the four mandatory-parameter checks, after tenant, namespace and sinkName.
Source
Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SinksImpl.java:100
final String sinkPkgUrl,
final SinkConfig sinkConfig,
final AuthenticationParameters authParams) {
if (!isWorkerServiceAvailable()) {
throwUnavailableException();
}
if (tenant == null) {
throw new RestException(Response.Status.BAD_REQUEST, "Tenant is not provided");
}
if (namespace == null) {
throw new RestException(Response.Status.BAD_REQUEST, "Namespace is not provided");
}
if (sinkName == null) {
throw new RestException(Response.Status.BAD_REQUEST, "Sink name is not provided");
}
if (sinkConfig == null) {
throw new RestException(Response.Status.BAD_REQUEST, "Sink config is not provided");
}
throwRestExceptionIfUnauthorizedForNamespace(tenant, namespace, sinkName, "register", authParams);
try {
// Check tenant exists
worker().getBrokerAdmin().tenants().getTenantInfo(tenant);
String qualifiedNamespace = tenant + "/" + namespace;
List<String> namespaces = worker().getBrokerAdmin().namespaces().getNamespaces(tenant);
if (namespaces != null && !namespaces.contains(qualifiedNamespace)) {
String qualifiedNamespaceWithCluster = String.format("%s/%s/%s", tenant,
worker().getWorkerConfig().getPulsarFunctionsCluster(), namespace);
if (namespaces != null && !namespaces.contains(qualifiedNamespaceWithCluster)) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sinkName)
.attr("namespace3", namespace).log("/ / Namespace does not exist");
throw new RestException(Response.Status.BAD_REQUEST, "Namespace does not exist");View on GitHub (pinned to 820761864e)
Solutions
- Send a complete SinkConfig JSON body with the request and set Content-Type: application/json.
- Verify the client-side deserialization: log the parsed SinkConfig before calling; if it is null, the body was empty or malformed.
- Construct the SinkConfig explicitly (className, topicToSerdeClassName/inputs) before registration.
Example fix
// before
curl -X PUT .../sinks/my-tenant/my-ns/my-sink # no body -> sinkConfig == null
// after
curl -X PUT .../sinks/my-tenant/my-ns/my-sink \
-H "Content-Type: application/json" \
-d '{"className":"org.example.MySink","inputs":"my-topic"}' Defensive patterns
Strategy: validation
Validate before calling
if (sinkConfig == null) {
throw new IllegalArgumentException("sinkConfig must be provided");
}
if (sinkConfig.getClassName() == null || sinkConfig.getClassName().isBlank()) {
throw new IllegalArgumentException("sinkConfig.className must be set");
} Type guard
boolean hasValidSinkConfig(SinkConfig cfg) {
return cfg != null && cfg.getClassName() != null && !cfg.getClassName().isBlank();
} Try / catch
try {
sinks.registerSink(tenant, ns, name, cfg, null, null, null, authParams);
} catch (RestException e) {
if (e.getResponse().getStatus() == 400 && "Sink config is not provided".equals(e.getMessage())) {
// the request body was missing or not deserialized; fix headers/body
} else { throw e; }
} Prevention
- Always send Content-Type: application/json with a non-empty body
- Log the deserialized SinkConfig client-side to catch silent null deserialization
- Build the config via a typed builder rather than ad-hoc JSON strings
When it happens
Trigger: Calling the sink registration endpoint without a request body, with an empty/unparsable body that deserializes to null SinkConfig, or passing null sinkConfig to SinksImpl.registerSink directly.
Common situations: curl requests missing -d/--data or the Content-Type: application/json header so the body is dropped; client SDKs failing silent JSON deserialization into null; scripts that build the config conditionally and skip it when inputs are empty.
Understand the failure class
Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.
Related errors
- Tenant is not provided
- Namespace is not provided
- Sink name is not provided
- <validation message from IllegalArgumentException>
- Path key doesn't match key in json
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/22d600e56ef9761b.
Report an issue: GitHub.