{"record":{"id":"53520d6ce91253f4","repo":"prestodb/presto","slug":"expected-field-to-be-s-actual-s-field-s","errorCode":null,"errorMessage":"Expected field to be %s, actual %s (field %s)","messagePattern":"Expected field to be (.+?), actual (.+?) \\(field (.+?)\\)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-hive/src/main/java/com/facebook/presto/hive/GenericHiveRecordCursor.java","lineNumber":581,"sourceCode":"        else if (DATE.equals(type)) {\n            parseLongColumn(column);\n        }\n        else if (TIMESTAMP.equals(type)) {\n            parseLongColumn(column);\n        }\n        else if (type instanceof DecimalType) {\n            parseDecimalColumn(column);\n        }\n        else {\n            throw new UnsupportedOperationException(\"Unsupported column type: \" + type);\n        }\n    }\n\n    private void validateType(int fieldId, Class<?> type)\n    {\n        if (!types[fieldId].getJavaType().equals(type)) {\n            // we don't use Preconditions.checkArgument because it requires boxing fieldId, which affects inner loop performance\n            throw new IllegalArgumentException(String.format(\"Expected field to be %s, actual %s (field %s)\", type, types[fieldId], fieldId));\n        }\n    }\n\n    @Override\n    public void close()\n    {\n        // some hive input formats are broken and bad things can happen if you close them multiple times\n        if (closed) {\n            return;\n        }\n        closed = true;\n\n        updateCompletedBytes();\n\n        try {\n            recordReader.close();\n        }\n        catch (IOException e) {","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-hive/src/main/java/com/facebook/presto/hive/GenericHiveRecordCursor.java#L563-L599","documentation":"GenericHiveRecordCursor.validateType asserts that the Java type requested from a cursor column (e.g. long.class, boolean.class) matches the column's declared type in the Hive schema. Presto's page-building machinery calls getLong/getBoolean/getDouble/getSlice/getObject with the expected type per column; a mismatch means the connector's column-to-type mapping is inconsistent with what the reader actually produces. The raw IllegalArgumentException (not a PrestoException) is deliberate to avoid boxing fieldId in the hot read loop.","triggerScenarios":"Calling cursor.getLong(field) (or getBoolean/getDouble/getSlice/getObject) on a field whose declared HiveColumnHandle type does not equal types[fieldId].getJavaType() — typically when a custom column handle or type mapping returns the wrong JavaType for that field position.","commonSituations":"Custom or third-party Hive readers (e.g. custom record cursor providers, ORC/Parquet reader plugins, query engines embedding the Hive connector) that build RecordCursor columns with mismatched type bindings; type registry/mapping changes after a Presto version upgrade; a reader provider that reorders columns without reordering types.","solutions":["Check that each HiveColumnHandle's getColumnType().getJavaType() matches the value type your cursor produces for that field index.","Verify column ordering: the types array passed to GenericHiveRecordCursor must align positionally with the columns list.","If a custom RecordCursorProvider is in use, fix it to construct column handles with types matching the underlying record reader's object inspectors.","If it appeared after a Presto/Hive connector upgrade, review TypeManager/TypeRegistry mapping changes for the affected Hive type."],"exampleFix":"// before\ncolumns.add(new HiveColumnHandle(\"extra\", 1, HIVE_INT, INTEGER, Optional.empty()));\n// after (type must match what validateType expects per get call)\ncolumns.add(new HiveColumnHandle(\"extra\", 1, HIVE_INT, BIGINT, Optional.empty())); // if cursor.getLong() is called","handlingStrategy":"type-guard","validationCode":"// validate column handle types before building the cursor\nfor (int i = 0; i < columns.size(); i++) {\n    if (!types[i].getJavaType().equals(expectedJavaTypes.get(i))) {\n        throw new IllegalStateException(\"Column \" + i + \" type mismatch: \" + types[i]);\n    }\n}","typeGuard":"boolean supportsRead(Class<?> actual, Class<?> requested) {\n    return actual != null && actual.equals(requested);\n}","tryCatchPattern":"try {\n    long v = cursor.getLong(field);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Expected field to be\")) {\n        throw new IllegalStateException(\"Column handle type mapping is wrong: \" + e.getMessage(), e);\n    }\n    throw e;\n}","preventionTips":["Derive column handles from a single source of truth so types and positions always align.","Unit-test custom record cursor providers against Hive table schemas with all supported types.","Re-verify type mappings after Presto upgrades, especially for DATE/TIMESTAMP/DECIMAL."],"tags":["presto","hive","type-mismatch","record-cursor"],"backgroundTag":"cursor-column-type-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"}