oracle/graal · error · IllegalArgumentException

Unexpected marker

Error message

Unexpected marker 

What it means

Thrown by BinaryReplayCodec.writeValue when a SpecialResultMarker value is neither NO_RESULT_MARKER nor NULL_RESULT_MARKER while serializing a compilation result marker. The codec only knows how to encode those two singleton markers (exception-throwing markers take a different branch), so any other SpecialResultMarker subtype is unencodable. It surfaces as an IllegalArgumentException during writing of a replay file.

Source

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

                out.writePackedUnsignedInt(doubles.length);
                for (double d : doubles) {
                    out.writeDoublePrimitive(d);
                }
            }
            case SpecialResultMarker.ExceptionThrownMarker marker -> {
                out.write(RESULT_MARKER_TAG);
                out.writePackedUnsignedInt(RESULT_EXCEPTION);
                writeValue(out, marker.getThrown(), state);
            }
            case SpecialResultMarker marker -> {
                out.write(RESULT_MARKER_TAG);
                int markerKind;
                if (marker == SpecialResultMarker.NO_RESULT_MARKER) {
                    markerKind = RESULT_NO_RESULT;
                } else if (marker == SpecialResultMarker.NULL_RESULT_MARKER) {
                    markerKind = RESULT_NULL;
                } else {
                    throw new IllegalArgumentException("Unexpected marker " + marker);
                }
                out.writePackedUnsignedInt(markerKind);
            }
            case StackTraceElement ste -> {
                out.write(STACK_TRACE_ELEMENT_TAG);
                writeStringReference(out, ste.getClassLoaderName(), state);
                writeStringReference(out, ste.getModuleName(), state);
                writeStringReference(out, ste.getModuleVersion(), state);
                writeStringReference(out, ste.getClassName(), state);
                writeStringReference(out, ste.getMethodName(), state);
                writeStringReference(out, ste.getFileName(), state);
                out.writePackedSignedInt(ste.getLineNumber());
            }
            case Register register -> {
                out.write(REGISTER_TAG);
                out.writePackedUnsignedInt(register.number);
            }
            case Field field -> {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. If you introduced a new SpecialResultMarker subtype, add a corresponding RESULT_* constant and a write branch (plus a matching read case in the RESULT_MARKER_TAG switch)
  2. If you control the value, pass only SpecialResultMarker.NO_RESULT_MARKER or NULL_RESULT_MARKER, or use the exception-thrown marker which is handled by its own case
  3. Check the marker before recording: filter unsupported markers out of the recorded result

Example fix

// before
SpecialResultMarker marker = myCustomMarker; // new subtype
writeValue(out, marker, state);

// after
if (marker == SpecialResultMarker.NO_RESULT_MARKER || marker == SpecialResultMarker.NULL_RESULT_MARKER
                || marker instanceof SpecialResultMarker.ExceptionThrownMarker) {
    writeValue(out, marker, state);
} else {
    throw new IllegalArgumentException("Unexpected marker " + marker);
}
Defensive patterns

Strategy: type-guard

Validate before calling

boolean encodable(SpecialResultMarker m) {
    return m == SpecialResultMarker.NO_RESULT_MARKER
        || m == SpecialResultMarker.NULL_RESULT_MARKER
        || m instanceof SpecialResultMarker.ExceptionThrownMarker;
}

Type guard

static boolean isEncodableMarker(Object v) {
    return v == SpecialResultMarker.NO_RESULT_MARKER
        || v == SpecialResultMarker.NULL_RESULT_MARKER
        || v instanceof SpecialResultMarker.ExceptionThrownMarker;
}

Try / catch

try {
    codec.writeResult(result);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unexpected marker")) {
        // skip recording this result or fail with context
    } else throw e;
}

Prevention

When it happens

Trigger: Calling the replay writer with a SpecialResultMarker instance that is a new subclass (e.g. a newly added marker kind) or a hand-constructed anonymous subclass; the pattern match 'case SpecialResultMarker marker' falls into the else branch and rejects it.

Common situations: Extending the replay-compilation framework with a new special result marker type without teaching the codec a new RESULT_* kind; passing test doubles or mocks of SpecialResultMarker into recorded compilation results.

Related errors


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