{"record":{"id":"918e8a9dde11b3c1","repo":"prestodb/presto","slug":"cannot-revoke-privilege-s-on-table-s-s","errorCode":null,"errorMessage":"Cannot revoke privilege %s on table %s%s","messagePattern":"Cannot revoke privilege (.+?) on table (.+?)(.+?)","errorType":"exception","errorClass":"AccessDeniedException","httpStatus":null,"severity":"error","filePath":"presto-spi/src/main/java/com/facebook/presto/spi/security/AccessDeniedException.java","lineNumber":332,"sourceCode":"\n    public static void denyGrantTablePrivilege(String privilege, String tableName)\n    {\n        denyGrantTablePrivilege(privilege, tableName, null);\n    }\n\n    public static void denyGrantTablePrivilege(String privilege, String tableName, String extraInfo)\n    {\n        throw new AccessDeniedException(format(\"Cannot grant privilege %s on table %s%s\", privilege, tableName, formatExtraInfo(extraInfo)));\n    }\n\n    public static void denyRevokeTablePrivilege(String privilege, String tableName)\n    {\n        denyRevokeTablePrivilege(privilege, tableName, null);\n    }\n\n    public static void denyRevokeTablePrivilege(String privilege, String tableName, String extraInfo)\n    {\n        throw new AccessDeniedException(format(\"Cannot revoke privilege %s on table %s%s\", privilege, tableName, formatExtraInfo(extraInfo)));\n    }\n\n    public static void denyShowRoles(String catalogName)\n    {\n        throw new AccessDeniedException(format(\"Cannot show roles from catalog %s\", catalogName));\n    }\n\n    public static void denyShowCurrentRoles(String catalogName)\n    {\n        throw new AccessDeniedException(format(\"Cannot show current roles from catalog %s\", catalogName));\n    }\n\n    public static void denyShowRoleGrants(String catalogName)\n    {\n        throw new AccessDeniedException(format(\"Cannot show role grants from catalog %s\", catalogName));\n    }\n\n    public static void denySetSystemSessionProperty(String propertyName)","sourceCodeStart":314,"sourceCodeEnd":350,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-spi/src/main/java/com/facebook/presto/spi/security/AccessDeniedException.java#L314-L350","documentation":"Thrown when the identity lacks the REVOKE privilege needed to remove a privilege from another principal on a table. denyRevokeTablePrivilege is invoked from AccessControlManager.checkCanRevokeTablePrivilege. Only grantors/admins may revoke.","triggerScenarios":"REVOKE SELECT ON t FROM USER u where checkCanRevokeTablePrivilege denies the current identity; revoking a grant made by a different admin you don't control.","commonSituations":"Security offboarding where the revoking account isn't an admin; connectors restricting revoke to catalog owners; mismatches between grantor and revoker identities.","solutions":["Execute the REVOKE as a catalog admin","Adjust access control rules to allow the account to revoke","Grant the account admin-level table privilege management"],"exampleFix":"// before\nREVOKE SELECT ON sales FROM USER carol; -- AccessDeniedException\n// after (as admin)\n-- admin executes:\nREVOKE SELECT ON sales FROM USER carol;","handlingStrategy":"try-catch","validationCode":"boolean canRevoke = catalogAdmin.isCatalogAdmin(revokingUser);","typeGuard":null,"tryCatchPattern":"try {\n    execute(\"REVOKE \" + privilege + \" ON \" + table + \" FROM USER \" + grantee);\n} catch (AccessDeniedException e) {\n    throw new SecurityException(\"Offboarding revokes must run as a catalog admin\", e);\n}","preventionTips":["Run revocation/offboarding jobs with a dedicated admin principal","Pair every GRANT with a documented REVOKE owner","Test revoke flows in staging with the same identity used in production"],"tags":["security","authorization","grants","revocation"],"backgroundTag":"access-denied","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}