{"record":{"id":"98aec28dae1f6cd6","repo":"prestodb/presto","slug":"role-already-exist","errorCode":"ROLE_ALREADY_EXIST","errorMessage":"Role '%s' already exists","messagePattern":"Role '(.+?)' already exists","errorType":"error_code","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"presto-main-base/src/main/java/com/facebook/presto/execution/CreateRoleTask.java","lineNumber":56,"sourceCode":"public class CreateRoleTask\n        implements DDLDefinitionTask<CreateRole>\n{\n    @Override\n    public String getName()\n    {\n        return \"CREATE ROLE\";\n    }\n\n    @Override\n    public ListenableFuture<?> execute(CreateRole statement, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, Session session, List<Expression> parameters, WarningCollector warningCollector, String query)\n    {\n        String catalog = createCatalogName(session, statement);\n        String role = statement.getName().getValueLowerCase();\n        Optional<PrestoPrincipal> grantor = statement.getGrantor().map(specification -> createPrincipal(session, specification));\n        accessControl.checkCanCreateRole(session.getRequiredTransactionId(), session.getIdentity(), session.getAccessControlContext(), role, grantor, catalog);\n        Set<String> existingRoles = metadata.listRoles(session, catalog);\n        if (existingRoles.contains(role)) {\n            throw new SemanticException(ROLE_ALREADY_EXIST, statement, \"Role '%s' already exists\", role);\n        }\n        if (grantor.isPresent() && grantor.get().getType() == ROLE && !existingRoles.contains(grantor.get().getName())) {\n            throw new SemanticException(MISSING_ROLE, statement, \"Role '%s' does not exist\", grantor.get().getName());\n        }\n        metadata.createRole(session, role, grantor, catalog);\n        return immediateFuture(null);\n    }\n}\n","sourceCodeStart":38,"sourceCodeEnd":65,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-main-base/src/main/java/com/facebook/presto/execution/CreateRoleTask.java#L38-L65","documentation":"CreateRoleTask.execute throws SemanticException(ROLE_ALREADY_EXIST) after checkCanCreateRole when metadata.listRoles shows the requested role name already exists in the target catalog. Role names are case-insensitive (lowercased before comparison), so 'Admin' and 'admin' collide. Presto refuses to create a duplicate rather than silently reusing it.","triggerScenarios":"CREATE ROLE <name> where the lowercased name already exists in the connector's role set for the statement's catalog.","commonSituations":"Idempotent provisioning scripts that re-run CREATE ROLE without IF NOT EXISTS semantics; case differences hiding an existing role; roles created in another catalog where listRoles for this catalog still reports it.","solutions":["Check existence first: query metadata.listRoles (or SHOW ROLES in the catalog) before issuing CREATE ROLE.","Use a different role name, since role names are lowercased and must be unique per catalog.","Wrap creation in your script's error handling to treat ROLE_ALREADY_EXIST as a no-op for idempotent runs.","If the role is stale/unwanted, drop it (DROP ROLE) and recreate with the desired definition."],"exampleFix":"-- before\nCREATE ROLE admin; -- fails if ADMIN already exists\n\n-- after\n-- only create if missing (script logic)\nIF 'admin' NOT IN (SELECT role_name FROM information_schema.roles WHERE catalog='hive') THEN\n  CREATE ROLE admin;\nEND IF;","handlingStrategy":"try-catch","validationCode":"Set<String> existing = metadata.listRoles(session, catalog);\nString role = statement.getName().getValueLowerCase();\nif (existing.contains(role)) {\n    // skip creation or choose another name\n    return;\n}","typeGuard":"boolean roleExists(String roleName, String catalog, Metadata metadata, Session session) {\n    return metadata.listRoles(session, catalog).contains(roleName.getValueLowerCase());\n}","tryCatchPattern":"try {\n    createRole(session, statement);\n} catch (SemanticException e) {\n    if (e.getCode() == ROLE_ALREADY_EXIST) {\n        // idempotent: treat as success\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always lowercase role names when checking existence, matching getValueLowerCase","Make role-provisioning scripts idempotent by catching ROLE_ALREADY_EXIST","Query SHOW ROLES / information_schema.roles before CREATE ROLE","Keep role names unique per catalog and avoid case-only differences"],"tags":["presto","role","duplicate","ddl","access-control"],"backgroundTag":"role-already-exists","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"}