prestodb/presto · error · AccessDeniedException

Cannot drop a branch from table %s%s

Error message

Cannot drop a branch from table %s%s

What it means

denyDropBranch throws AccessDeniedException when the access control layer denies dropping a branch from the given table. Presto checks DROP BRANCH authorization before executing the statement; connectors call denyDropBranch(tableName, extraInfo) to raise it.

Source

Thrown at presto-spi/src/main/java/com/facebook/presto/spi/security/AccessDeniedException.java:447

    public static void denyCreateTag(String tableName)
    {
        denyCreateTag(tableName, null);
    }

    public static void denyCreateTag(String tableName, String extraInfo)
    {
        throw new AccessDeniedException(format("Cannot create tag on table %s%s", tableName, formatExtraInfo(extraInfo)));
    }

    public static void denyDropBranch(String tableName)
    {
        denyDropBranch(tableName, null);
    }

    public static void denyDropBranch(String tableName, String extraInfo)
    {
        throw new AccessDeniedException(format("Cannot drop a branch from table %s%s", tableName, formatExtraInfo(extraInfo)));
    }

    public static void denyDropTag(String tableName)
    {
        denyDropTag(tableName, null);
    }

    public static void denyDropTag(String tableName, String extraInfo)
    {
        throw new AccessDeniedException(format("Cannot drop a tag from table %s%s", tableName, formatExtraInfo(extraInfo)));
    }

    public static void denyDropConstraint(String tableName)
    {
        denyDropConstraint(tableName, null);
    }

    public static void denyDropConstraint(String tableName, String extraInfo)

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Grant DROP BRANCH (or table ownership/admin) to the user/group in the access-control policy
  2. Verify the user is matching the intended principal in the policy (impersonation, group membership, Kerberos/LDAP mapping)
  3. Use a service account with the required privileges for automated branch lifecycle jobs
  4. If the branch should not be droppable, that is expected behavior — switch to expiring snapshots instead

Example fix

// before
{"catalog": "iceberg", "group": "analysts", "privileges": ["SELECT"]}
// after
{"catalog": "iceberg", "group": "analysts", "privileges": ["SELECT", "DROP BRANCH"]}
Defensive patterns

Strategy: try-catch

Validate before calling

// check DROP BRANCH privilege before destructive branch cleanup
if (!grants(user, catalog, table).contains("DROP BRANCH")) {
    throw new IllegalStateException("DROP BRANCH not granted");
}

Type guard

boolean canDropBranch(String user, String table, Map<String, Set<String>> grants) {
    return grants.getOrDefault(user, Set.of()).stream().anyMatch(g -> g.startsWith(table) && g.endsWith("DROP BRANCH"));
}

Try / catch

try {
    conn.execute("ALTER TABLE t DROP BRANCH b");
} catch (AccessDeniedException e) {
    LOG.warn("DROP BRANCH denied: %s", e.getMessage());
    // rethrow or fall back to requesting elevated credentials
    throw e;
}

Prevention

When it happens

Trigger: A connector calls checkCanDropBranch; the policy rejects and calls denyDropBranch, producing 'Cannot drop a branch from table <table><extraInfo>'.

Common situations: Users cleaning up old branches on tables they can read but not administer; dropping branches created by other users/roles; overly strict policy plugins that never grant destructive operations.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/ebecc73a89994d4a. Report an issue: GitHub.