apache/flink · error · RuntimeException

Could not instantiate record

Error message

Could not instantiate record

What it means

Thrown when JavaRecordBuilderFactory.build() cannot invoke a Java record's canonical constructor via Constructor.newInstance(). The RuntimeException wraps the reflective cause, which can be illegal access (non-public record), wrong argument count/types (schema evolution remapping mismatch), or an exception thrown by the record's compact constructor itself.

Source

Thrown at flink-core/src/main/java/org/apache/flink/api/java/typeutils/runtime/JavaRecordBuilderFactory.java:91

    /** Builder class for incremental record construction. */
    @Internal
    final class JavaRecordBuilder {
        private final Object[] args;

        JavaRecordBuilder() {
            if (defaultConstructorArgs == null) {
                args = new Object[canonicalConstructor.getParameterCount()];
            } else {
                args = Arrays.copyOf(defaultConstructorArgs, defaultConstructorArgs.length);
            }
        }

        T build() {
            try {
                return canonicalConstructor.newInstance(args);
            } catch (Exception e) {
                throw new RuntimeException("Could not instantiate record", e);
            }
        }

        /**
         * Set record field by index. If parameter index mapping is provided, the index is mapped,
         * otherwise it is used as is.
         *
         * @param i index of field to be set
         * @param value field value
         */
        void setField(int i, Object value) {
            if (paramIndexMapping != null) {
                args[paramIndexMapping[i]] = value;
            } else {
                args[i] = value;
            }
        }
    }

View on GitHub (pinned to 2f3c205e92)

Solutions

  1. Inspect the wrapped cause in the stack trace (e.getCause()) - it names the real failure: access, argument mismatch, or constructor exception
  2. Make the record class public (top-level or a public nested type) so the canonical constructor is invocable
  3. If restoring old state, verify the record's component names/types match what the serializer snapshot expects, or realign fields so argIndexMapping is correct
  4. Fix the record's compact constructor if it rejects valid default values for newly added components

Example fix

// before: package-private record
record Event(String id, long ts) {}

// after: public record
public record Event(String id, long ts) {}
Defensive patterns

Strategy: validation

Validate before calling

if (!Modifier.isPublic(recordClass.getModifiers())) {
    throw new IllegalArgumentException("Record class must be public: " + recordClass);
}
if (!recordClass.isRecord()) {
    throw new IllegalArgumentException("Not a record: " + recordClass);
}

Type guard

static boolean isInstantiableRecord(Class<?> c) {
    if (!c.isRecord() || !Modifier.isPublic(c.getModifiers())) {
        return false;
    }
    try {
        c.getDeclaredConstructor().setAccessible(true);
        return true;
    } catch (ReflectiveOperationException | RuntimeException e) {
        return false;
    }
}

Try / catch

try {
    T value = builder.build();
} catch (RuntimeException e) {
    Throwable cause = e.getCause(); // IllegalAccessException | InvocationTargetException | IllegalArgumentException
    throw new IllegalStateException("Record instantiation failed: " + cause, cause);
}

Prevention

When it happens

Trigger: Deserializing or copying a Java record through Kryo/POJO serialization paths (e.g. KryoSerializer or PojoSerializer reading a record): canonicalConstructor.newInstance(args) throws IllegalAccessException, IllegalArgumentException, or InvocationTargetException; also when argIndexMapping from schema migration feeds mis-typed values.

Common situations: Record class is package-private or nested without being accessible to the user-code classloader; record read from a savepoint/checkpoint written with a different record layout (added/removed/reordered components); record compact constructor validates and throws on restored default values; user-code classloader isolation between the serializer and the record class.

Related errors


AI-assisted analysis of apache/flink@2f3c205e92 (2026-08-14). Data as JSON: /api/errors/af8131e0bd914225. Report an issue: GitHub.