{"record":{"id":"6ece419744f2e218","repo":"apache/druid","slug":"authresult-geterrormessage-6ece41","errorCode":null,"errorMessage":"authResult.getErrorMessage()","messagePattern":"authResult\\.getErrorMessage\\(\\)","errorType":"http","errorClass":"ForbiddenException","httpStatus":403,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java","lineNumber":157,"sourceCode":"          catch (UOE e) {\n            return Response.status(Response.Status.BAD_REQUEST)\n                           .entity(\n                               ImmutableMap.of(\n                                   \"error\",\n                                   e.getMessage()\n                               )\n                           )\n                           .build();\n          }\n\n          AuthorizationResult authResult = AuthorizationUtils.authorizeAllResourceActions(\n              req,\n              resourceActions,\n              authorizerMapper\n          );\n\n          if (!authResult.allowAccessWithNoRestriction()) {\n            throw new ForbiddenException(authResult.getErrorMessage());\n          }\n          try {\n            spec.validateSpec();\n          }\n          catch (DruidException e) {\n            return Response.status(Response.Status.BAD_REQUEST)\n                           .entity(ImmutableMap.of(\"error\", e.getMessage()))\n                           .build();\n          }\n\n          final SupervisorSpecUpdateResult updateResult =\n              manager.createOrUpdateAndStartSupervisor(spec, Boolean.TRUE.equals(skipRestartIfUnmodified));\n\n          if (updateResult.isModified() || updateResult.isRestarted()) {\n            auditSupervisorUpdate(spec, req);\n          }\n\n          return Response.ok(","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/overlord/supervisor/SupervisorResource.java#L139-L175","documentation":"SupervisorResource's specPost endpoint performs an authorization check (via AuthorizerMapper/AuthConfig) before validating and creating a supervisor spec. If the authResult does not allow access with no restriction, it throws ForbiddenException using the authorization result's error message. This is Druid's standard per-resource action check: the authenticated user lacks a required action (e.g. WRITE on DATASOURCE) for the supplied supervisor spec.","triggerScenarios":"POST /druid/indexer/v1/supervisor (specPost) where the authenticated user/role fails the authorization check against the configured authorizer: required action (typically WRITE) on the target datasource resource is denied, or the resource identified in the spec is filtered out by the user's authorizer prefix.","commonSituations":"Operators calling the supervisor API with a service account whose role lacks write permission on the datasource; using an identity that only has READ; misconfigured druid.auth authenticator/authorizer roles missing the datasource in permissions; Kerberos/LDAP users without the expected group mappings.","solutions":["Grant the user's role a WRITE permission (type DATASOURCE, name = the spec's datasource, or wildcard '.*') in the authorizer JSON in coordinator dynamic config or authorizer config.","Verify which authenticator/authorizer identity is being used (check the request's authentication result / auth logs) and fix credentials if the wrong identity is resolved.","Check that the datasource name in the supervisor spec matches the resource patterns in the role; adjust the role or the spec.","If access should be unrestricted, adjust druid.auth.authorizers / AuthConfig to use an authorizer that allows the request."],"exampleFix":"// before: role has only READ permission\n{\"name\": \"myRole\", \"permissions\": [{\"resource\": {\"type\": \"DATASOURCE\", \"name\": \"wiki\"}, \"action\": \"READ\"}]}\n// after: add WRITE so supervisor POST is authorized\n{\"name\": \"myRole\", \"permissions\": [{\"resource\": {\"type\": \"DATASOURCE\", \"name\": \"wiki\"}, \"action\": \"READ\"}, {\"resource\": {\"type\": \"DATASOURCE\", \"name\": \"wiki\"}, \"action\": \"WRITE\"}]}","handlingStrategy":"try-catch","validationCode":"// check user permissions before POSTing the supervisor spec\nfetch('/druid/indexer/v1/authorizer/test', {method:'POST', body: JSON.stringify({resource:{type:'DATASOURCE',name:spec.spec.dataSchema.dataSource}, action:'WRITE'})});","typeGuard":null,"tryCatchPattern":"try { postSupervisor(spec); } catch (WebApplicationException e) { if (e.getResponse().getStatus() == 403) { handleForbidden(e.getResponse().readEntity(String.class)); } else { throw e; } }","preventionTips":["Grant WRITE on DATASOURCE to roles that manage supervisors","Verify the identity used for API calls has authorizer roles configured","Keep the datasource name in the spec aligned with role permission patterns"],"tags":["authorization","http-api","supervisor","druid"],"backgroundTag":"permission-denied","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}