prestodb/presto · error · AccessDeniedException

Cannot add a constraint to table %s%s

Error message

Cannot add a constraint to table %s%s

What it means

denyAddConstraint throws AccessDeniedException when the access control layer denies adding a constraint to the given table. Adding constraints (e.g. primary keys, check constraints) is authorized via checkCanAddConstraint before the connector applies the change.

Source

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

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

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

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

    public static void denyAddConstraint(String tableName, String extraInfo)
    {
        throw new AccessDeniedException(format("Cannot add a constraint to table %s%s", tableName, formatExtraInfo(extraInfo)));
    }

    private static Object formatExtraInfo(String extraInfo)
    {
        if (extraInfo == null || extraInfo.isEmpty()) {
            return "";
        }
        return ": " + extraInfo;
    }
}

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Grant ADD CONSTRAINT / ALTER privilege to the principal in the access-control policy
  2. Confirm the DDL targets a table covered by an existing allow rule (wildcards vs explicit names)
  3. Use a privileged migration account for schema governance changes
  4. If the connector/catalog does not support the constraint type, use an alternative mechanism instead of forcing policy changes

Example fix

// before
{"catalog": "hive", "group": "data-eng", "privileges": ["SELECT", "INSERT"]}
// after
{"catalog": "hive", "group": "data-eng", "privileges": ["SELECT", "INSERT", "ADD CONSTRAINT"]}
Defensive patterns

Strategy: try-catch

Validate before calling

// confirm ADD CONSTRAINT grant before DDL
if (!grants(user, catalog, table).contains("ADD CONSTRAINT")) {
    throw new IllegalStateException("ADD CONSTRAINT not granted");
}

Type guard

boolean canAddConstraint(String user, String table, Map<String, Set<String>> grants) {
    return grants.getOrDefault(user, Set.of()).stream().anyMatch(g -> g.contains("ADD CONSTRAINT"));
}

Try / catch

try {
    conn.execute("ALTER TABLE t ADD CONSTRAINT pk_t PRIMARY KEY (id)");
} catch (AccessDeniedException e) {
    LOG.warn("ADD CONSTRAINT denied: %s", e.getMessage());
    throw e;
}

Prevention

When it happens

Trigger: A connector calls checkCanAddConstraint; its policy rejects the operation and calls denyAddConstraint(tableName, extraInfo), producing 'Cannot add a constraint to table <table><extraInfo>'.

Common situations: Enforcing data-integrity constraints in governance-heavy environments where DDL is locked down; users with table write but not alter privileges; policies enumerating privileges and missing ADD CONSTRAINT.

Related errors


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