apache/flink · error · RuntimeException
Serializer does not support named field positions.
Error message
Serializer does not support named field positions.
What it means
RowSerializer.copyNameBased() is invoked when the source Row has named fields (getFieldNames() returns non-null). It requires the serializer to have been constructed with a positionByName map (field-name → position). If positionByName is null — meaning the serializer was built for position-based Rows only — this RuntimeException is thrown. The serializer cannot map named fields to positions it was never given.
Source
Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/RowSerializer.java:170
+ "this serializer's field length ("
+ length
+ ").");
}
final Object[] fieldByPosition = new Object[length];
for (int i = 0; i < length; i++) {
final Object fromField = from.getField(i);
if (fromField != null) {
final Object copy = fieldSerializers[i].copy(fromField);
fieldByPosition[i] = copy;
}
}
return RowUtils.createRowWithNamedPositions(
from.getKind(), fieldByPosition, positionByName);
}
private Row copyNameBased(Row from, Set<String> fieldNames) {
if (positionByName == null) {
throw new RuntimeException("Serializer does not support named field positions.");
}
final Row newRow = Row.withNames(from.getKind());
for (String fieldName : fieldNames) {
final int targetPos = getPositionByName(fieldName);
final Object fromField = from.getField(fieldName);
if (fromField != null) {
final Object copy = fieldSerializers[targetPos].copy(fromField);
newRow.setField(fieldName, copy);
} else {
newRow.setField(fieldName, null);
}
}
return newRow;
}
@Override
public Row copy(Row from, Row reuse) {
// cannot reuse, do a non-reuse copyView on GitHub (pinned to 2f3c205e92)
Solutions
- Construct the RowSerializer (or RowTypeInfo) WITH field names so positionByName is populated: pass a LinkedHashMap<String,Integer> as the second constructor argument.
- Ensure all Rows in the pipeline use the same mode (all position-based or all name-based consistently).
- If the data is truly name-based, build the TypeInformation with named fields so the serializer is constructed with the name→position map.
- Convert name-based Rows to position-based before serializing if the serializer cannot be changed.
Example fix
// before — position-based serializer receiving a name-based Row
RowSerializer ser = new RowSerializer(new TypeSerializer[]{intSer, strSer});
Row named = Row.withNames().setField("id", 1).setField("name", "a");
ser.copy(named); // positionByName == null → exception
// after — construct serializer with field-name map
LinkedHashMap<String, Integer> names = new LinkedHashMap<>();
names.put("id", 0); names.put("name", 1);
RowSerializer ser = new RowSerializer(new TypeSerializer[]{intSer, strSer}, names);
ser.copy(named); // positionByName != null → OK Defensive patterns
Strategy: type-guard
Validate before calling
// Check whether the serializer supports name-based Rows before using them
public static boolean supportsNamedFields(RowSerializer ser) {
// positionByName is private; infer by testing with createInstance
Row probe = ser.createInstance();
return probe.getFieldNames(false) != null;
}
// Or simply ensure you always construct with names when needed
public static RowSerializer withNames(TypeSerializer<?>[] sers, String... names) {
LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
for (int i = 0; i < names.length; i++) map.put(names[i], i);
return new RowSerializer(sers, map);
} Type guard
public static boolean isNameBasedRow(Row row) {
return row.getFieldNames(false) != null;
}
// Before serializing a name-based Row, ensure the serializer was built with names:
public static boolean serializerSupportsNames(RowSerializer ser) {
return ser.createInstance().getFieldNames(false) != null;
} Try / catch
try {
serializer.copy(namedRow);
} catch (RuntimeException e) {
if (e.getMessage().contains("does not support named field positions")) {
log.error("Serializer is position-based; rebuild with field names or "
+ "convert the Row to position-based mode");
}
throw e;
} Prevention
- Construct RowSerializer (and RowTypeInfo) with field names if any Rows in the pipeline are name-based.
- Standardize the pipeline on one Row mode.
- Validate Row mode at the source.
- Build TypeInformation with explicit field names matching the source schema.
When it happens
Trigger: RowSerializer.copy(Row) receives a name-based Row (created via Row.withNames()), but the RowSerializer was constructed via the single-argument constructor RowSerializer(TypeSerializer<?>[]) which sets positionByName = null.
Common situations: The RowTypeInfo was built without field names, but the data stream carries name-based Rows (e.g., produced by a source that emits Row.withNames()); a Table-to-DataStream bridge or a connector emits named Rows into a pipeline whose serializer was configured for positional Rows; mixing name-based and position-based Row creation in the same pipeline.
Related errors
- Row arity of from ({}) does not match this serializer's fiel
- Row arity of reuse ({}) or from ({}) is incompatible with th
- Row arity of record ({}) does not match this serializer's fi
- Unknown field name '%s' for mapping to a row position. Avail
- Row arity of reuse ({}) does not match this serializer's fie
AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14).
Data as JSON: /api/errors/35843a622fdaf569.
Report an issue: GitHub.