{"record":{"id":"16665900a3813fce","repo":"apache/druid","slug":"authresult-geterrormessage","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/http/OverlordResource.java","lineNumber":185,"sourceCode":"  )\n  {\n    final Set<ResourceAction> resourceActions;\n    try {\n      resourceActions = getNeededResourceActionsForTask(task);\n    }\n    catch (UOE e) {\n      return Response.status(Response.Status.BAD_REQUEST)\n                     .entity(ImmutableMap.of(\"error\", e.getMessage()))\n                     .build();\n    }\n\n    AuthorizationResult authResult = AuthorizationUtils.authorizeAllResourceActions(\n        req,\n        resourceActions,\n        authorizerMapper\n    );\n    if (!authResult.allowAccessWithNoRestriction()) {\n      throw new ForbiddenException(authResult.getErrorMessage());\n    }\n\n    return asLeaderWith(\n        taskMaster.getTaskQueue(),\n        taskQueue -> {\n          try {\n            taskQueue.add(task);\n\n            if (AUDITED_TASK_TYPES.contains(task.getType())) {\n              auditManager.doAudit(\n                  AuditEntry.builder()\n                            .key(task.getDataSource())\n                            .type(\"task\")\n                            .request(AuthorizationUtils.buildRequestInfo(\"overlord\", req))\n                            .payload(new TaskIdentifier(task.getId(), task.getGroupId(), task.getType()))\n                            .auditInfo(AuthorizationUtils.buildAuditInfo(req))\n                            .build()\n              );","sourceCodeStart":167,"sourceCodeEnd":203,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/overlord/http/OverlordResource.java#L167-L203","documentation":"The POST task endpoint (taskPost) authorizes all resource actions implied by the submitted task. If the authenticated user is not granted access (result does not allow access with no restriction), it throws ForbiddenException with the authorization failure message.","triggerScenarios":"POSTing a task to /druid/indexer/v1/task with credentials lacking required READ/WRITE access to the task's datasource — e.g. a role with only READ on the datasource, or a task touching a datasource outside the user's allowed set.","commonSituations":"Service accounts provisioned without ingestion permissions; tasks writing to new datasources the user cannot WRITE; misconfigured authorizer roles after a security rollout.","solutions":["Grant the submitting user WRITE (and required READ) permissions on the datasource in their Authorizer role.","Use credentials of a service account with the required datasource permissions.","Use the authResult message to identify the denied resource/action and add exactly that permission."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  postTask(taskJson);\n} catch (ForbiddenException | WebApplicationException e) {\n  if (((WebApplicationException) e).getResponse().getStatus() == 403) {\n    // request WRITE on the datasource for the submitting identity\n  }\n}","preventionTips":["Provision ingestion service accounts with datasource WRITE permissions.","Keep task datasources within the set the identity is authorized for.","Audit authorizer roles after adding new datasources."],"tags":["druid","overlord","authorization","forbidden"],"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"}