prestodb/presto · error · PrestoException

INVALID_COLUMN_MASK

INVALID_COLUMN_MASK

Error message

Multiple masks for the same column found

What it means

When computing column masks, AccessControlManager merges system-level and catalog-level masks into an ImmutableSetMultimap keyed by column and calls buildOrThrow(). Presto allows at most one mask per column, so duplicate keys make buildOrThrow throw IllegalArgumentException, which is rethrown as PrestoException with code INVALID_COLUMN_MASK.

Source

Thrown at presto-main-base/src/main/java/com/facebook/presto/security/AccessControlManager.java:1008

        requireNonNull(columns, "columns is null");

        ImmutableMap.Builder<ColumnMetadata, ViewExpression> columnMasksBuilder = ImmutableMap.builder();

        // connector-provided masks take precedence over global masks
        CatalogAccessControlEntry entry = getConnectorAccessControl(transactionId, tableName.getCatalogName());
        if (entry != null) {
            Map<ColumnMetadata, ViewExpression> connectorMasks = entry.getAccessControl().getColumnMasks(entry.getTransactionHandle(transactionId), identity.toConnectorIdentity(tableName.getCatalogName()), context, toSchemaTableName(tableName), columns);
            columnMasksBuilder.putAll(connectorMasks);
        }

        Map<ColumnMetadata, ViewExpression> systemMasks = systemAccessControl.getColumnMasks(identity, context, toCatalogSchemaTableName(tableName), columns);
        columnMasksBuilder.putAll(systemMasks);

        try {
            return columnMasksBuilder.buildOrThrow();
        }
        catch (IllegalArgumentException exception) {
            throw new PrestoException(INVALID_COLUMN_MASK, "Multiple masks for the same column found", exception);
        }
    }

    private CatalogAccessControlEntry getConnectorAccessControl(TransactionId transactionId, String catalogName)
    {
        return transactionManager.getOptionalCatalogMetadata(transactionId, catalogName)
                .map(metadata -> connectorAccessControl.get(metadata.getConnectorId()))
                .orElse(null);
    }

    @Managed
    @Nested
    public CounterStat getAuthenticationSuccess()
    {
        return authenticationSuccess;
    }

    @Managed

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Audit system and catalog access control configs and remove all but one mask per column
  2. Consolidate the masking logic into a single mask expression that covers both requirements
  3. Assign the masks to different scopes (e.g. keep only the system mask and delete the connector mask, or vice versa)
  4. Catch INVALID_COLUMN_MASK at deploy/validate time and log which column is double-masked

Example fix

// before: system mask AND catalog mask both on users.email
// after: keep a single mask
{
  "system_access_control": "file",
  "catalog_access_controls": [{ "name": "file", "config.properties": "catalog.properties" }]
}
// remove the duplicate email column mask from one of the two configs
Defensive patterns

Strategy: validation

Validate before calling

// detect duplicate mask targets in access control JSON before deploy
// jq -r '.columnMasks[] | .catalog+"."+.schema+"."+.table+"."+.column' config.json | sort | uniq -d

Try / catch

try {
    masks = accessControlManager.getColumnMasks(...);
} catch (PrestoException e) {
    if (e.getErrorCode() == INVALID_COLUMN_MASK.toErrorCode()) {
        log.error("Deduplicate column masks in access control configuration");
    } else { throw e; }
}

Prevention

When it happens

Trigger: Two or more configured column masks (from system access control and/or catalog/connector access control entries) target the same (catalog, schema, table, column) — e.g. systemMasks plus a connector mask on the same column.

Common situations: Layering access control configs where both a system-level file-based control and a connector-level control define a mask for the same column; duplicated rules in a JSON access control config after a merge or migration; incremental policy edits that added a second mask instead of replacing the existing one.

Related errors


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