{"record":{"id":"1503077639da0420","repo":"prestodb/presto","slug":"hive-column-order-mismatch","errorCode":"HIVE_COLUMN_ORDER_MISMATCH","errorMessage":"Partition keys must be the last columns in the table and in the same order as the table properties: ","messagePattern":"Partition keys must be the last columns in the table and in the same order as the table properties: ","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java","lineNumber":3645,"sourceCode":"\n    private static void validatePartitionColumns(ConnectorTableMetadata tableMetadata)\n    {\n        List<String> partitionedBy = getPartitionedBy(tableMetadata.getProperties());\n\n        List<String> allColumns = tableMetadata.getColumns().stream()\n                .map(ColumnMetadata::getName)\n                .collect(toList());\n\n        if (!allColumns.containsAll(partitionedBy)) {\n            throw new PrestoException(INVALID_TABLE_PROPERTY, format(\"Partition columns %s not present in schema\", Sets.difference(ImmutableSet.copyOf(partitionedBy), ImmutableSet.copyOf(allColumns))));\n        }\n\n        if (allColumns.size() == partitionedBy.size()) {\n            throw new PrestoException(INVALID_TABLE_PROPERTY, \"Table contains only partition columns\");\n        }\n\n        if (!allColumns.subList(allColumns.size() - partitionedBy.size(), allColumns.size()).equals(partitionedBy)) {\n            throw new PrestoException(HIVE_COLUMN_ORDER_MISMATCH, \"Partition keys must be the last columns in the table and in the same order as the table properties: \" + partitionedBy);\n        }\n    }\n\n    protected Optional<TableEncryptionProperties> getTableEncryptionPropertiesFromTableProperties(ConnectorTableMetadata tableMetadata, HiveStorageFormat hiveStorageFormat, List<String> partitionedBy)\n    {\n        ColumnEncryptionInformation columnEncryptionInformation = getEncryptColumns(tableMetadata.getProperties());\n        String tableEncryptionReference = getEncryptTable(tableMetadata.getProperties());\n\n        if (tableEncryptionReference == null && (columnEncryptionInformation == null || !columnEncryptionInformation.hasEntries())) {\n            return Optional.empty();\n        }\n\n        if (tableEncryptionReference != null && columnEncryptionInformation.hasEntries()) {\n            throw new PrestoException(INVALID_TABLE_PROPERTY, format(\"Only one of %s or %s should be specified\", ENCRYPT_TABLE, ENCRYPT_COLUMNS));\n        }\n\n        if (hiveStorageFormat != DWRF) {\n            throw new PrestoException(NOT_SUPPORTED, \"Only DWRF file format supports encryption at this time\");","sourceCodeStart":3627,"sourceCodeEnd":3663,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-hive/src/main/java/com/facebook/presto/hive/HiveMetadata.java#L3627-L3663","documentation":"Hive tables declare partition columns via the 'partitioned_by' table property, and Hive requires those columns to appear physically as the LAST columns of the table schema, in exactly the same order as listed in the property. During CREATE TABLE (or table validation in HiveMetadata), Presto compares the suffix of the column list against the partitioned_by list; any mismatch throws HIVE_COLUMN_ORDER_MISMATCH.","triggerScenarios":"CREATE TABLE ... WITH (partitioned_by = ARRAY['a','b']) where columns 'a'/'b' are not the final columns, or where they appear in a different order than in the property. Also thrown when partition columns are interspersed among regular columns instead of trailing.","commonSituations":"Hand-writing DDL converted from another engine; adding a new regular column after table creation without reordering; tooling that appends columns alphabetically; mismatch between partitioned_by ordering and actual column order after schema edits.","solutions":["Reorder the table columns so all partition columns come last, matching the partitioned_by order exactly.","Rewrite the partitioned_by property to list the trailing columns in the same order they appear in the schema.","Move any non-partition columns that were appended after the partition columns to before them (e.g. drop/recreate the table with correct order)."],"exampleFix":"-- before\nCREATE TABLE t (ds VARCHAR, id BIGINT, country VARCHAR)\nWITH (partitioned_by = ARRAY['ds', 'country']);\n\n-- after\nCREATE TABLE t (id BIGINT, ds VARCHAR, country VARCHAR)\nWITH (partitioned_by = ARRAY['ds', 'country']);","handlingStrategy":"validation","validationCode":"// Validate before running CREATE TABLE\nList<String> partitionedBy = List.of(\"ds\", \"country\");\nList<String> allColumns = columns.stream().map(ColumnMetadata::getName).collect(toList());\nif (!allColumns.subList(allColumns.size() - partitionedBy.size(), allColumns.size()).equals(partitionedBy)) {\n    throw new IllegalArgumentException(\"Partition columns must be the last columns, in partitioned_by order\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always define partition columns last in the schema and mirror that exact order in partitioned_by.","Generate DDL from a single source of truth for columns+partitions instead of hand-writing both lists.","Re-validate ordering after any ALTER that appends or renames columns."],"tags":["hive","partitioning","ddl","schema"],"backgroundTag":"partition-column-order-mismatch","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"}