apache/iceberg · error · IllegalArgumentException
Cannot find projected field:
Error message
Cannot find projected field:
What it means
Thrown by SupportsIndexProjection when building an index-based projection mapping: a projected field from the requested schema cannot be located in the source Avro schema fields by field ID. The library cannot construct the position array used to project values, so record reading cannot proceed.
Solutions
- Ensure all Avro schema fields carry the correct 'field-id' (iceberg-field-id) attribute matching the Iceberg schema
- Verify the data file schema is in sync with the current table schema; rewrite/repair stale files
- Make newly added fields optional so missing values can be filled with null instead of failing projection
- Regenerate the read schema from the table schema via AvroSchemaUtil rather than hand-editing
Example fix
// before
Schema readSchema = new Schema(Optional.of("t"), required(5, "notes", StringType.get()));
// after
Schema readSchema = new Schema(Optional.of("t"), optional(5, "notes", StringType.get())); Defensive patterns
Strategy: validation
Validate before calling
Set<Integer> ids = table.schema().columns().stream().map(Types.NestedField::fieldId).collect(Collectors.toSet());
Schema fileSchema = AvroSchemaUtil.readSchema(file).orElseThrow();
for (Types.NestedField f : readSchema.columns()) {
Object id = fileSchema.asStruct().field(f.name()) != null ? f.fieldId() : null;
if (id == null || !ids.contains(f.fieldId())) throw new IllegalStateException("field-id missing for " + f.name());
} Type guard
boolean hasField(Schema schema, Types.NestedField f) { return Arrays.stream(schema.getFields().toArray(new Field[0])).anyMatch(x -> x.getProp(AvroSchemaUtil.FIELD_ID_PROP) != null); } Try / catch
try (CloseableIterable<Record> rows = Avro.read(file).project(table.schema()).build()) { rows.forEach(...); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Cannot find projected field")) { /* resync schema / rewrite files */ } else throw e; } Prevention
- Always keep field-id properties in Avro schemas produced or transformed by external tools
- Prefer optional columns for schema evolution
- Rewrite old files after required-column additions
- Use AvroSchemaUtil.convert from the table schema instead of hand-built schemas
When it happens
Trigger: Reading an Avro data or manifest file whose schema lacks a field that the table schema (or a projection of it) declares; typically a stale data file written by an older schema after the table added a required field.
Common situations: Schema evolution (field added as required) combined with old data files; custom Avro schemas missing field IDs; manually constructed read schemas where field-id properties were stripped by tools.
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
- Missing required 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…
- Avro does not support AAD prefix
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/1fa6b288cd87ac69.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/avro/SupportsIndexProjection.java:53
}
/** Base constructor for building the type mapping */
protected SupportsIndexProjection(Types.StructType baseType, Types.StructType projectionType) {
List<Types.NestedField> allFields = baseType.fields();
List<Types.NestedField> fields = projectionType.fields();
this.fromProjectionPos = new int[fields.size()];
for (int i = 0; i < fromProjectionPos.length; i += 1) {
boolean found = false;
for (int j = 0; j < allFields.size(); j += 1) {
if (fields.get(i).fieldId() == allFields.get(j).fieldId()) {
found = true;
fromProjectionPos[i] = j;
}
}
if (!found) {
throw new IllegalArgumentException("Cannot find projected field: " + fields.get(i));
}
}
}
/** Constructor with a precomputed position mapping */
protected SupportsIndexProjection(int[] fromProjectionPos) {
this.fromProjectionPos = fromProjectionPos;
}
/** Copy constructor */
protected SupportsIndexProjection(SupportsIndexProjection toCopy) {
this.fromProjectionPos = toCopy.fromProjectionPos;
}
protected abstract <T> T internalGet(int pos, Class<T> javaClass);
protected abstract <T> void internalSet(int pos, T value);
View on GitHub (pinned to 86d9c8fc54)