apache/iceberg · error · IllegalArgumentException
Missing ORC reader for field
Error message
Missing ORC reader for field %s (%s)
What it means
StructReader builds a per-position array of ORC value readers for each field of an Iceberg struct. When a projected field is neither a metadata column, an UNKNOWN-typed field, nor covered by a reader produced from the ORC file schema, it throws IllegalArgumentException. This indicates the ORC file schema cannot satisfy the requested read schema.
Solutions
- Ensure the ORC file was written by Iceberg with field IDs embedded in the ORC type description, or set table property schema.name-mapping.default so field IDs can be resolved by name.
- Check that the read schema's field IDs exist in the file's ORC schema; re-read with the file-compatible schema or rewrite the files via Iceberg rewrite/compact.
- Update to a recent Iceberg version if the file was written by a much older writer with a different ORC field-ID convention.
Example fix
// before: reading old files with new schema, no name mapping
table.updateProperties().set(TableProperties.DEFAULT_NAME_MAPPING, "{\"type\":\"struct\",\"fields\":[...id...\"]}").commit();
// after: name mapping present, field IDs resolvable, read succeeds Defensive patterns
Strategy: validation
Validate before calling
// Verify every read-schema field exists in the ORC file schema (or has a name mapping)
NameMapping mapping = Optional.ofNullable(table.properties().get(TableProperties.DEFAULT_NAME_MAPPING))
.map(Mappings::fromJson).orElse(null);
for (Types.NestedField f : expectedSchema.columns()) {
if (MetadataColumns.metadataFieldIds().contains(f.fieldId())) continue;
if (MappingCreateVisitor.find(mapping, f.fieldId()) == null && orcSchema.findField(f.fieldId()) == null) {
throw new IllegalArgumentException("Field " + f.fieldId() + " missing from ORC file");
}
} Prevention
- Always write ORC via Iceberg so field IDs are embedded in the ORC schema
- Set schema.name-mapping.default when importing external ORC files
- Check field IDs after schema evolution; rewrite old files before dropping name mappings
When it happens
Trigger: Calling ORC reads (e.g. via OrcBatchReader/Spark/Flink ORC scans) with an expected schema containing a field whose fieldId has no corresponding ORC column and is not a metadata column or UNKNOWN type — typically a schema-evolution mismatch where the file predates the field.
Common situations: Reading ORC files written before a column was added to the table schema; a wrong/renamed write.schema vs read schema; using a custom ORC writer that did not embed Iceberg field IDs; case where nameMapping is absent so field-ID mapping fails.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- ORC cannot read default value for field
- Altering schema is not supported in the old alterTable API…
- Altering schema is not supported in the old alterTable API…
- Altering schema is not supported in the old alterTable API…
- Batch reading is not supported in non-vectorized reader
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/cfe76a8e834e7e38.
Report an issue: GitHub.
Appendix: source
Thrown at orc/src/main/java/org/apache/iceberg/orc/OrcValueReaders.java:223
} else if (idToConstant.containsKey(field.fieldId())) {
this.isConstantOrMetadataField[pos] = true;
this.readers[pos] = constants(idToConstant.get(field.fieldId()));
} else if (field.equals(MetadataColumns.ROW_POSITION)) {
this.isConstantOrMetadataField[pos] = true;
this.readers[pos] = new RowPositionReader();
} else if (field.equals(MetadataColumns.IS_DELETED)) {
this.isConstantOrMetadataField[pos] = true;
this.readers[pos] = constants(false);
} else if (fileReader != null) {
this.isConstantOrMetadataField[pos] = false;
this.orcFieldIndex[pos] = fieldIdToOrcIndex.getOrDefault(field.fieldId(), -1);
this.readers[pos] = fileReader;
} else if (MetadataColumns.isMetadataColumn(field.name())
|| field.type().typeId() == Type.TypeID.UNKNOWN) {
this.isConstantOrMetadataField[pos] = true;
this.readers[pos] = constants(null);
} else {
throw new IllegalArgumentException(
String.format("Missing ORC reader for field %s (%s)", field.name(), field.fieldId()));
}
}
}
private Map<Integer, Integer> buildFieldIdToOrcIndex(TypeDescription orcType) {
List<TypeDescription> children = orcType.getChildren();
Map<Integer, Integer> mapping = Maps.newHashMap();
for (int i = 0; i < children.size(); i++) {
mapping.put(ORCSchemaUtil.fieldId(children.get(i)), i);
}
return mapping;
}
private Map<Integer, OrcValueReader<?>> readersByFieldId(
TypeDescription orcType, List<OrcValueReader<?>> readerList) {
List<TypeDescription> children = orcType.getChildren();View on GitHub (pinned to 86d9c8fc54)