oracle/graal · error · IOException

Invalid ordinal ${ordinal} for ${enumClassName}

Error message

Invalid ordinal ${ordinal} for ${enumClassName}

What it means

readEnumOrdinals rebuilds an EnumSet from ordinal integers, bounds-checking each ordinal against enumClass.getEnumConstants().length. An ordinal outside [0, length) throws IOException 'Invalid ordinal <ordinal> for <enum class>'. This is the classic record/replay enum-skew failure: the recording JVM's enum had more constants (or a different order) than the replaying JVM's.

Source

Thrown at compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/hotspot/replaycomp/BinaryReplayCodec.java:1180

            default -> throw new IOException("Unknown replay architecture kind");
        };
    }

    private static void writeEnumOrdinals(ObjectCopierOutputStream out, EnumSet<?> enumSet) throws IOException {
        out.writePackedUnsignedInt(enumSet.size());
        for (Enum<?> constant : enumSet) {
            out.writePackedUnsignedInt(constant.ordinal());
        }
    }

    private static <E extends Enum<E>> EnumSet<E> readEnumOrdinals(ObjectCopierInputStream in, Class<E> enumClass) throws IOException {
        int size = in.readPackedUnsignedInt();
        EnumSet<E> enumSet = EnumSet.noneOf(enumClass);
        E[] constants = enumClass.getEnumConstants();
        for (int i = 0; i < size; i++) {
            int ordinal = in.readPackedUnsignedInt();
            if (ordinal < 0 || ordinal >= constants.length) {
                throw new IOException("Invalid ordinal " + ordinal + " for " + enumClass.getName());
            }
            enumSet.add(constants[ordinal]);
        }
        return enumSet;
    }

    private static int registerConfigKind(RegisterConfig registerConfig) {
        return switch (registerConfig) {
            case AMD64HotSpotRegisterConfig ignored -> AMD64_ARCHITECTURE;
            case RISCV64HotSpotRegisterConfig ignored -> RISCV64_ARCHITECTURE;
            case AArch64HotSpotRegisterConfig ignored -> AARCH64_ARCHITECTURE;
            default -> throw new IllegalArgumentException("Unexpected register config " + registerConfig);
        };
    }

    @SuppressWarnings("unchecked")
    private static RegisterConfig readRegisterConfig(ObjectCopierInputStream in, ReadState state) throws IOException {
        int kind = in.readPackedUnsignedInt();

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Re-record the replay file on the same JDK/GraalVM build used for replay
  2. Check enum constant counts match: recording build's CPUFeature.values().length must equal the replaying build's
  3. If a constant was only appended (no reorder) and the reader is older, upgrade the reader to a build containing the extra constants

Example fix

// before
EnumSet<AMD64.CPUFeature> fs = readEnumOrdinals(in, AMD64.CPUFeature.class);

// after
// pre-flight compatibility check before replay
int recordedMax = maxRecordedOrdinal(file);
if (recordedMax >= AMD64.CPUFeature.values().length) {
    throw new IOException("CPUFeature enum skew: re-record replay file on this build");
}
Defensive patterns

Strategy: validation

Validate before calling

static <E extends Enum<E>> boolean ordinalsInRange(Class<E> ec, int... ords) {
    int n = ec.getEnumConstants().length;
    for (int o : ords) if (o < 0 || o >= n) return false;
    return true;
}

Try / catch

try {
    result = codec.readReplay(in);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Invalid ordinal")) {
        // enum skew (e.g. CPUFeature changed): re-record on this build
    } else throw e;
}

Prevention

When it happens

Trigger: Replaying CPU feature sets or other enum sets recorded on a build where the enum had extra/reordered constants; corrupted packed ints in a feature list.

Common situations: JDK or GraalVM upgrade between record and replay that changed a CPUFeature enum (e.g. new CPU features appended then removed); cross-build replay of architecture descriptions.

Related errors


AI-assisted analysis of oracle/graal@a66e9ccd1d (2026-08-14). Data as JSON: /api/errors/67d087c9c4e95a91. Report an issue: GitHub.