dotnet/runtime · error · RuntimeError
Error, unclean replay.
Error message
Error, unclean replay.
What it means
Raised in `__verify_final_mch__` (superpmi.py:1478-1479), only reached when `--clean` is set. After cleaning, it replays the final MCH against the same JIT used for collection; if SuperPMIReplay.replay() returns False (any context failed), the collection is considered non-deterministic/unclean and rejected. A clean collection must replay every context error-free.
Source
Thrown at src/coreclr/scripts/superpmi.py:1479
if not os.path.isfile(self.toc_file):
raise RuntimeError("Error, toc file not created correctly at: %s" % self.toc_file)
def __verify_final_mch__(self):
""" Verify the resulting MCH file is error-free when running SuperPMI against it with the same JIT used for collection.
Notes:
<SuperPmiPath> -p -f <s_finalFailMclFile> <s_finalMchFile> <jitPath>
"""
logging.info("Verifying MCH file")
mch_files = [ self.final_mch_file ]
spmi_replay = SuperPMIReplay(self.coreclr_args, mch_files, self.jit_path)
passed = spmi_replay.replay()
if not passed:
raise RuntimeError("Error, unclean replay.")
def __process_for_ci__(self):
""" Helix doesn't upload zero-sized files. Sometimes we end up with zero-sized .mch files if
there is no data collected. Convert these to special "sentinel" files that are later processed
by "merge-mch" by deleting them. This prevents the <HelixWorkItem.DownloadFilesFromResults>
file download to succeed (because the file exists) and the MCH merge to also succeed.
"""
logging.info("Process MCH files for CI")
if os.path.getsize(self.final_mch_file) == 0:
# Convert to sentinel file
logging.info("Converting zero-length MCH file {} to ZEROLENGTH sentinel file".format(self.final_mch_file))
with open(self.final_mch_file, "w") as write_fh:
write_fh.write("ZEROLENGTH")
################################################################################
# SuperPMI Replay helpersView on GitHub (pinned to 290d5ab72c)
Solutions
- Re-run the collection with `--clean` (it strips failing contexts) until replay passes; if it never passes, investigate the failing context reported by the replay.
- Ensure tiering is explicitly controlled (--tiered_compilation / --tiered_pgo) so collection is deterministic.
- Confirm the JIT used for the verification replay is the same clrjit used during collection (same Core_Root/build).
Defensive patterns
Strategy: retry
Validate before calling
# Best-effort: ensure deterministic collection env before clean+verify # (determinism is enforced via DOTNET_ vars; nothing to validate offline) pass
Try / catch
attempt = 0
passed = False
while not passed and attempt < 3:
attempt += 1
try:
collection.__verify_final_mch__()
passed = True
except RuntimeError as e:
if 'unclean replay' not in str(e):
raise
logging.warning('unclean replay on attempt %d; re-running clean', attempt)
collection.__create_clean_mch_file__() # strip more failing contexts
if not passed:
raise SystemExit('MCH never replayed cleanly after retries') Prevention
- Pin tiering state (--tiered_compilation / --tiered_pgo) for determinism.
- Use the same clrjit for collection and verification.
When it happens
Trigger: Collecting with `--clean` where the verification replay of the final MCH with the collection JIT reports at least one failing context. This indicates the JIT did not deterministically reproduce some captured method contexts.
Common situations: Non-deterministic JIT behavior (e.g. randomness/tiering leaking in), time- or thread-dependent compilations, an MCH that still contains contexts that fail to replay after stripping, or using a JIT build that differs subtly from the collection-time JIT.
Related errors
- Final mch file failed to be generated.
- MCH file failed to be generated at: %s
- Error, toc file not created correctly at: %s
- No .mc files generated.
- No active session to reconnect
AI-assisted analysis of dotnet/runtime@290d5ab72c (2026-08-06).
Data as JSON: /api/errors/7229d7e8f2d2beed.
Report an issue: GitHub.