oracle/graal · error · IOException

Unknown replay tag

Error message

Unknown replay tag 

What it means

The terminal default of readValue's top-level tag switch: the first byte read for a value is a tag the codec does not recognize, so it throws IOException 'Unknown replay tag <tag>'. Because every subsequent parse is positioned off this tag byte, an unknown tag means the reader and writer disagree on the format or the stream is misaligned/corrupt.

Source

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

            }
            case ARCHITECTURE_TAG -> {
                Architecture architecture = readArchitecture(in);
                state.setArchitecture(architecture);
                yield architecture;
            }
            case TARGET_DESCRIPTION_TAG ->
                new TargetDescription((Architecture) readValue(in, state), readBooleanFlag(in), in.readPackedSignedInt(), in.readPackedSignedInt(), readBooleanFlag(in));
            case REGISTER_CONFIG_TAG -> readRegisterConfig(in, state);
            case EXCEPTION_HANDLER_TAG ->
                new ExceptionHandler(in.readPackedSignedInt(), in.readPackedSignedInt(), in.readPackedSignedInt(), in.readPackedSignedInt(), (JavaType) readValue(in, state));
            case THROWABLE_TAG ->
                createThrowable(requireNonNullString(readStringReference(in, state), "throwable class"), readStringReference(in, state));
            case COMPILATION_TASK_EXCEPTION_TAG ->
                new CompilationTaskProduct.CompilationTaskException(requireNonNullString(readStringReference(in, state), "task exception class"),
                                requireNonNullString(readStringReference(in, state), "task exception stack trace"));
            case RECORDED_TASK_ARTIFACTS_TAG ->
                new CompilationTaskProduct.RecordedCompilationTaskArtifacts(requireNonNullString(readStringReference(in, state), "final graph"));
            default -> throw new IOException("Unknown replay tag " + tag);
        };
    }

    private static void writeProperties(ObjectCopierOutputStream out, Map<String, String> properties, WriteState state) throws IOException {
        if (properties == null) {
            out.writePackedUnsignedInt(0);
            return;
        }
        out.writePackedUnsignedInt(properties.size() + 1);
        for (Map.Entry<String, String> entry : properties.entrySet()) {
            writeStringReference(out, entry.getKey(), state);
            writeStringReference(out, entry.getValue(), state);
        }
    }

    private static Map<String, String> readProperties(ObjectCopierInputStream in, ReadState state) throws IOException {
        int encodedSize = in.readPackedUnsignedInt();
        if (encodedSize == 0) {

View on GitHub (pinned to a66e9ccd1d)

Solutions

  1. Regenerate the replay file with the exact GraalVM build used for replay
  2. Check the file version via verifyHeader passes before full decode
  3. If adding new tags in a fork, bump VERSION so older readers reject the file up front instead of mid-stream

Example fix

// before
default -> throw new IOException("Unknown replay tag " + tag);

// after
// prevention: gate on the version read in verifyHeader
int version = readVersion(file);
if (version != VERSION) throw new IOException("Unsupported replay file version " + version);
Defensive patterns

Strategy: validation

Validate before calling

// cheap structural pre-check before full decode
static boolean looksLikeReplayFile(java.nio.file.Path p) throws IOException {
    byte[] magic = java.nio.file.Files.readAllBytes(p);
    return magic.length > 0 && magic[0] == BinaryReplayCodec.MAGIC[0];
}

Try / catch

try {
    result = codec.readReplay(in);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Unknown replay tag")) {
        // treat as corrupt or version-skewed file; discard and re-record
    } else throw e;
}

Prevention

When it happens

Trigger: Replaying a binary written by a codec version with extra tags; any earlier parse error left the cursor misaligned, so the next tag byte is arbitrary data; truncated files where reads return garbage.

Common situations: Replay file version mismatch (writer newer than reader); corrupted or partially-written replay files (process killed mid-write); introducing new tags without bumping the file VERSION.

Related errors


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