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
- Check the instance's current status (GET .../{instanceId}/status) and only start when STOPPED / stop when RUNNING.
- Treat the 400 "Operation not permitted" response as a no-op if the desired end state is already achieved.
- Serialize start/stop operations to avoid racing transitions.
- 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
- Check instance status before start/stop; make transitions conditional.
- Serialize lifecycle operations per component to avoid races.
- Validate instanceId against the configured instance count.
- Design orchestrators to tolerate already-satisfied transitions.
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
- The log error handler cannot be changed once the appender is
- javaInstanceRunnable is not initialized
- FunctionArchive is already closed
- Connector is already closed
- ${fullFunctionName} doesn't exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/895ef3caa68f5578.
Report an issue: GitHub.