apache/pulsar · warning · RestException

Update contains no change

Error message

Update contains no change

What it means

After merging the submitted SinkConfig with the existing one, updateSink rejects the request with HTTP 400 "Update contains no change" when the merged config equals the existing config AND no new package URL, no uploaded package file, and no UpdateOptions.isUpdateAuthData flag were supplied. The worker refuses no-op updates because they would needlessly bump metadata versions.

Source

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

        SinkConfig existingSinkConfig = SinkConfigUtils.convertFromDetails(existingComponent.getFunctionDetails());
        // The rest end points take precedence over whatever is there in functionconfig
        sinkConfig.setTenant(tenant);
        sinkConfig.setNamespace(namespace);
        sinkConfig.setName(sinkName);

        SinkConfig mergedConfig;
        try {
            mergedConfig = SinkConfigUtils.validateUpdate(existingSinkConfig, sinkConfig);
        } catch (Exception e) {
            throw new RestException(Response.Status.BAD_REQUEST, e.getMessage());
        }

        if (existingSinkConfig.equals(mergedConfig) && isBlank(sinkPkgUrl) && uploadedInputStream == null
                && (updateOptions == null || !updateOptions.isUpdateAuthData())) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sinkName)

                    .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,
                        sinkPkgUrl,
                        existingComponent.getPackageLocation().getPackagePath(),
                        uploadedInputStream);
                functionDetails = validateUpdateRequestParams(tenant, namespace, sinkName,
                        mergedConfig, componentPackageFile);
                if (existingComponent.getPackageLocation().getPackagePath().startsWith(Utils.BUILTIN)
                        && !isFunctionCodeBuiltin(functionDetails)
                        && (componentPackageFile == null || fileDetail == null)) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the update actually changes something; skip the call if the config is unchanged.
  2. Pass UpdateOptions with updateAuthData=true if the intent is to refresh auth data.
  3. Provide a new packageUrl or upload a new archive if the code changed.
  4. Diff your payload against GET /admin/v3/sinks/{tenant}/{namespace}/{name} before submitting.

Example fix

// before: PUT with unchanged config -> 400
admin.sinks().updateSink(tenant, ns, name, sameConfig, null, null);
// after: signal an intentional no-config update
UpdateOptions opts = UpdateOptions.builder().updateAuthData(true).build();
admin.sinks().updateSink(tenant, ns, name, sameConfig, null, null, opts);
Defensive patterns

Strategy: validation

Validate before calling

SinkConfig current = admin.sinks().getSinkConfig(tenant, ns, name);
if (current.equals(newConfig)) {
    return; // skip no-op update
}

Try / catch

try {
    admin.sinks().updateSink(tenant, ns, name, cfg, pkgUrl, null);
} catch (PulsarAdminException e) {
    if ("Update contains no change".equals(e.getMessage())) {
        log.info("No-op update skipped");
    }
}

Prevention

When it happens

Trigger: PUT /admin/v3/sinks/{tenant}/{namespace}/{name} with a body identical to the current sink config, no sinkPkgUrl/uploadedInputStream, and updateOptions null or updateAuthData=false.

Common situations: Idempotent deployment scripts re-applying the same config; accidentally posting the config fetched from GET unchanged; retry after a failed update that had already taken effect.

Related errors


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