prestodb/presto · error · SemanticException

MISMATCHED_COLUMN_ALIASES

MISMATCHED_COLUMN_ALIASES

Error message

Column alias list has %s entries but subquery has %s columns

What it means

Presto throws this SemanticException when an ALIAS clause (e.g. in a table or UNNEST relation) supplies a different number of column aliases than the subquery/underlying relation produces columns. The analyzer validates the alias list against the actual column count during query analysis before execution. This is a static SQL-semantic error, not a runtime data error.

Solutions

  1. Count the columns produced by the subquery and make the alias list exactly the same length.
  2. Remove the alias list entirely (e.g. `t` instead of `t(a, b, c)`) if named columns are not required.
  3. Update the alias list automatically whenever the subquery projection changes; add a query-formatting/lint check in CI.
  4. If caught programmatically, catch com.facebook.presto.sql.analyzer.SemanticException and check getErrorCode() == MISMATCHED_COLUMN_ALIASES to surface a clear message to the end user.

Example fix

// before
SELECT * FROM (SELECT id, name, created_at FROM users) u(id, name)
// after
SELECT * FROM (SELECT id, name, created_at FROM users) u(id, name, created_at)
Defensive patterns

Strategy: validation

Validate before calling

int projected = countProjectionColumns(subquerySql); // via metadata or a lightweight parser
if (aliasList != null && aliasList.size() != projected) {
    throw new IllegalArgumentException("alias list has " + aliasList.size() + " entries but subquery has " + projected + " columns");
}

Try / catch

try { runQuery(sql); } catch (SemanticException e) { if ("MISMATCHED_COLUMN_ALIASES".equals(e.getCode().getName())) { fixAliasListAndRetry(sql); } else { throw e; } }

Prevention

When it happens

Trigger: Writing `SELECT * FROM (SELECT 1, 2, 3) t(a, b)` or a table-valued/relation reference with a column alias list whose length (2) does not equal the subquery's column count (3). validateColumnAliases compares columnAliases.size() to sourceColumnSize and throws on inequality.

Common situations: Hand-edited queries where a subquery was later changed to add/remove columns but the alias list was not updated; ORM or query-builder generated aliases drifting from the projection; copy-pasting an alias list from a similar but wider table definition.

Related errors


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

Appendix: source

Thrown at presto-main-base/src/main/java/com/facebook/presto/sql/analyzer/StatementAnalyzer.java:1628

            Set<String> names = new HashSet<>();
            for (Field field : descriptor.getVisibleFields()) {
                Optional<String> fieldName = field.getName();
                if (!fieldName.isPresent()) {
                    throw new SemanticException(COLUMN_NAME_NOT_SPECIFIED, node, "Column name not specified at position %s", descriptor.indexOf(field) + 1);
                }
                if (!names.add(fieldName.get())) {
                    throw new SemanticException(DUPLICATE_COLUMN_NAME, node, "Column name '%s' specified more than once", fieldName.get());
                }
                if (field.getType().equals(UNKNOWN)) {
                    throw new SemanticException(COLUMN_TYPE_UNKNOWN, node, "Column type is unknown: %s", fieldName.get());
                }
            }
        }

        private void validateColumnAliases(List<Identifier> columnAliases, int sourceColumnSize)
        {
            if (columnAliases.size() != sourceColumnSize) {
                throw new SemanticException(
                        MISMATCHED_COLUMN_ALIASES,
                        columnAliases.get(0),
                        "Column alias list has %s entries but subquery has %s columns",
                        columnAliases.size(),
                        sourceColumnSize);
            }
            Set<String> names = new HashSet<>();
            for (Identifier identifier : columnAliases) {
                if (names.contains(identifier.getValueLowerCase())) {
                    throw new SemanticException(DUPLICATE_COLUMN_NAME, identifier, "Column name '%s' specified more than once", identifier.getValue());
                }
                names.add(identifier.getValueLowerCase());
            }
        }

        private void validateBaseTables(List<Table> baseTables, Node node)
        {
            for (Table baseTable : baseTables) {

View on GitHub (pinned to 55bb57d202)