{"record":{"id":"895ef3caa68f5578","repo":"apache/pulsar","slug":"operation-not-permitted","errorCode":null,"errorMessage":"Operation not permitted","messagePattern":"Operation not permitted","errorType":"http","errorClass":"RestException","httpStatus":400,"severity":"warning","filePath":"pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java","lineNumber":668,"sourceCode":"        }\n\n        FunctionMetaData functionMetaData =\n                functionMetaDataManager.getFunctionMetaData(tenant, namespace, componentName);\n        if (!InstanceUtils.calculateSubjectType(functionMetaData.getFunctionDetails()).equals(componentType)) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", componentName)\n\n                    .attr(\"componentType\", ComponentTypeUtils.toString(componentType)).log(\"/ / is not a\");\n            throw new RestException(Status.NOT_FOUND,\n                    String.format(\"%s %s doesn't exist\", ComponentTypeUtils.toString(componentType), componentName));\n        }\n\n        if (!FunctionMetaDataUtils.canChangeState(functionMetaData, Integer.parseInt(instanceId),\n                start ? org.apache.pulsar.functions.proto.FunctionState.RUNNING\n                        : org.apache.pulsar.functions.proto.FunctionState.STOPPED)) {\n            log.error().attr(\"tenant\", tenant).attr(\"namespace\", namespace).attr(\"componentName\", componentName)\n\n                    .log(\"Operation not permitted on / /\");\n            throw new RestException(Status.BAD_REQUEST, \"Operation not permitted\");\n        }\n\n        FunctionMetaData newFunctionMetaData = FunctionMetaDataUtils\n                .changeFunctionInstanceStatus(functionMetaData, Integer.parseInt(instanceId), start);\n        internalProcessFunctionRequest(tenant, namespace, componentName, newFunctionMetaData, false,\n                String.format(\"Failed to start/stop %s: %s/%s/%s/%s\", ComponentTypeUtils.toString(componentType),\n                        tenant, namespace, componentName, instanceId));\n    }\n\n    @Override\n    public void restartFunctionInstance(final String tenant,\n                                        final String namespace,\n                                        final String componentName,\n                                        final String instanceId,\n                                        final URI uri,\n                                        final AuthenticationParameters authParams) {\n        if (!isWorkerServiceAvailable()) {\n            throwUnavailableException();","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/ComponentImpl.java#L650-L686","documentation":"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\".","triggerScenarios":"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.","commonSituations":"Idempotent-looking start/stop calls in orchestration loops; race where two operators stop the same instance; instanceId beyond the configured instance count.","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."],"exampleFix":"// before\nadmin.functions().stopFunction(t, n, fn, 0); // 400 if already stopped\n// after\nFunctionStatus s = admin.functions().getFunctionStatus(t, n, fn, 0);\nif (s.isRunning()) { admin.functions().stopFunction(t, n, fn, 0); }","handlingStrategy":"validation","validationCode":"FunctionStatus s = admin.functions().getFunctionStatus(t, n, fn, instanceId);\nboolean canProceed = (start && !s.isRunning()) || (!start && s.isRunning());\nif (!canProceed) { /* skip: already in desired state */ }","typeGuard":null,"tryCatchPattern":"try { admin.functions().stopFunction(t, n, fn, id); }\ncatch (PulsarAdminException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Operation not permitted\")) {\n        log.info(\"instance already in desired state\"); // treat as no-op\n    } else throw e;\n}","preventionTips":["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."],"tags":["pulsar-functions","http-400","illegal-state-transition","lifecycle"],"backgroundTag":"illegal-state-transition","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}