apache/pulsar · warning · RestException

Operation not permitted

Error message

Operation not permitted

What it means

Thrown by changeFunctionInstanceStatus when FunctionMetaDataUtils.canChangeState rejects the requested transition — e.g. trying to start an already-running instance or stop an already-stopped one, or the instanceId is out of range. Returned as HTTP 400 BAD_REQUEST with the fixed message "Operation not permitted".

Source

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

        }

        FunctionMetaData functionMetaData =
                functionMetaDataManager.getFunctionMetaData(tenant, namespace, componentName);
        if (!InstanceUtils.calculateSubjectType(functionMetaData.getFunctionDetails()).equals(componentType)) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", componentName)

                    .attr("componentType", ComponentTypeUtils.toString(componentType)).log("/ / is not a");
            throw new RestException(Status.NOT_FOUND,
                    String.format("%s %s doesn't exist", ComponentTypeUtils.toString(componentType), componentName));
        }

        if (!FunctionMetaDataUtils.canChangeState(functionMetaData, Integer.parseInt(instanceId),
                start ? org.apache.pulsar.functions.proto.FunctionState.RUNNING
                        : org.apache.pulsar.functions.proto.FunctionState.STOPPED)) {
            log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", componentName)

                    .log("Operation not permitted on / /");
            throw new RestException(Status.BAD_REQUEST, "Operation not permitted");
        }

        FunctionMetaData newFunctionMetaData = FunctionMetaDataUtils
                .changeFunctionInstanceStatus(functionMetaData, Integer.parseInt(instanceId), start);
        internalProcessFunctionRequest(tenant, namespace, componentName, newFunctionMetaData, false,
                String.format("Failed to start/stop %s: %s/%s/%s/%s", ComponentTypeUtils.toString(componentType),
                        tenant, namespace, componentName, instanceId));
    }

    @Override
    public void restartFunctionInstance(final String tenant,
                                        final String namespace,
                                        final String componentName,
                                        final String instanceId,
                                        final URI uri,
                                        final AuthenticationParameters authParams) {
        if (!isWorkerServiceAvailable()) {
            throwUnavailableException();

View on GitHub (pinned to 820761864e)

Solutions

  1. Check the instance's current status (GET .../{instanceId}/status) and only start when STOPPED / stop when RUNNING.
  2. Treat the 400 "Operation not permitted" response as a no-op if the desired end state is already achieved.
  3. Serialize start/stop operations to avoid racing transitions.
  4. Validate instanceId against the component's configured instance count.

Example fix

// before
admin.functions().stopFunction(t, n, fn, 0); // 400 if already stopped
// after
FunctionStatus s = admin.functions().getFunctionStatus(t, n, fn, 0);
if (s.isRunning()) { admin.functions().stopFunction(t, n, fn, 0); }
Defensive patterns

Strategy: validation

Validate before calling

FunctionStatus s = admin.functions().getFunctionStatus(t, n, fn, instanceId);
boolean canProceed = (start && !s.isRunning()) || (!start && s.isRunning());
if (!canProceed) { /* skip: already in desired state */ }

Try / catch

try { admin.functions().stopFunction(t, n, fn, id); }
catch (PulsarAdminException e) {
    if (e.getMessage() != null && e.getMessage().contains("Operation not permitted")) {
        log.info("instance already in desired state"); // treat as no-op
    } else throw e;
}

Prevention

When it happens

Trigger: POST start on an instance whose FunctionState is already RUNNING, or stop on an already STOPPED instance (or any state transition disallowed by canChangeState for the given instanceId), on the function/sink/source start-stop endpoints.

Common situations: Idempotent-looking start/stop calls in orchestration loops; race where two operators stop the same instance; instanceId beyond the configured instance count.

Related errors


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