apache/pulsar · warning · RestException
Update contains no change
Error message
Update contains no change
What it means
updateSource rejects a request that would produce no effect: the merged SourceConfig equals the existing one, no package URL and no uploaded package file are supplied, and updateOptions either is null or does not request auth-data update. The worker short-circuits with 400 BAD_REQUEST instead of performing a pointless metadata update.
Source
Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java:324
SourceConfig existingSourceConfig =
SourceConfigUtils.convertFromDetails(existingComponent.getFunctionDetails());
// The rest end points take precedence over whatever is there in functionconfig
sourceConfig.setTenant(tenant);
sourceConfig.setNamespace(namespace);
sourceConfig.setName(sourceName);
SourceConfig mergedConfig;
try {
mergedConfig = SourceConfigUtils.validateUpdate(existingSourceConfig, sourceConfig);
} catch (Exception e) {
throw new RestException(Response.Status.BAD_REQUEST, e.getMessage());
}
if (existingSourceConfig.equals(mergedConfig) && isBlank(sourcePkgUrl) && uploadedInputStream == null
&& (updateOptions == null || !updateOptions.isUpdateAuthData())) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)
.log("/ / Update contains no changes");
throw new RestException(Response.Status.BAD_REQUEST, "Update contains no change");
}
FunctionDetails functionDetails;
File componentPackageFile = null;
try {
// validate parameters
try {
componentPackageFile = getPackageFile(
componentType,
sourcePkgUrl,
existingComponent.getPackageLocation().getPackagePath(),
uploadedInputStream);
functionDetails = validateUpdateRequestParams(tenant, namespace, sourceName,
mergedConfig, componentPackageFile);
if (existingComponent.getPackageLocation().getPackagePath().startsWith(Utils.BUILTIN)
&& !isFunctionCodeBuiltin(functionDetails)
&& (componentPackageFile == null || fileDetail == null)) {View on GitHub (pinned to 820761864e)
Solutions
- Change something real: modify a mutable field in the SourceConfig (e.g. configs, parallelism, processing guarantees)
- Provide a new package via sourcePkgUrl or upload the package in the request
- If the update is only about secrets/auth data, pass UpdateOptions with updateAuthData=true
- If the no-op is intentional, skip the API call — compare the existing config to the desired one before invoking update
Example fix
// before
admin.sources().updateSource(tenant, ns, name, sameConfig);
// after
UpdateOptions opts = new UpdateOptions();
opts.setUpdateAuthData(true); // if only refreshing auth data
admin.sources().updateSource(tenant, ns, name, sameConfig, opts);
// or skip entirely:
if (!existing.equals(desired)) { admin.sources().updateSource(...); } Defensive patterns
Strategy: validation
Validate before calling
SourceConfig existing = admin.sources().getSourceConfig(tenant, ns, name);
SourceConfig merged = SourceConfigUtils.validateUpdate(existing, desired);
boolean authData = opts != null && opts.isUpdateAuthData();
if (existing.equals(merged) && pkgUrl == null && uploadStream == null && !authData) {
log.info("Skipping no-op source update for {}", name);
} else {
admin.sources().updateSource(tenant, ns, name, desired, opts);
} Try / catch
try {
admin.sources().updateSource(tenant, ns, name, cfg);
} catch (PulsarAdminException e) {
if (e.getMessage() != null && e.getMessage().contains("no change")) {
log.info("Source {} already up to date", name); // treat as success
} else { throw e; }
} Prevention
- Compare desired state with current state before issuing updates
- Idempotently skip PUTs when the fetched config equals the desired config
- Set updateAuthData=true only when secrets actually changed
When it happens
Trigger: PUT /admin/v3/sources/{tenant}/{namespace}/{sourceName} where the submitted config is byte-for-byte equivalent to the stored config after merging, isBlank(sourcePkgUrl), uploadedInputStream == null, and updateOptions == null || !updateOptions.isUpdateAuthData().
Common situations: Re-running an automation/deployment script that applies a desired state already applied; resubmitting the same config fetched from GET; a CI job that always PUTs the source config even when nothing changed.
Related errors
- <validation message from IllegalArgumentException>
- %s %s doesn't have instance with id %s
- Function in trigger function has more than 1 input topics
- Function in trigger function has unidentified topic
- %s Package is not provided
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/1b304be408a8bab7.
Report an issue: GitHub.