Recover a damaged MCAP into a new file, then check its message coverage against the recording you expected. Exit code 0 does not prove that all expected data survived. In our MCAP CLI 0.3.0 test, a clean cut after seven of ten messages returned 0; a cut inside the eighth returned 3. Both recovered exactly the same seven messages.
If a robot computer lost power or a copied log ends early, use the recovered subset for the topics and time span you can account for. An expected end event, another recorder or a recording manifest supplies the evidence that the damaged file itself cannot provide.
Recover a copy and inspect what survived
The official MCAP CLI guide documents doctor and recover. This example uses the tested Windows binary, mcap-cli v0.3.0. Check --version and the installed command’s --help before using flags from a newer guide.
In PowerShell, start with damaged.mcap and choose unused working and output paths:
if ((Test-Path -LiteralPath '.\working.mcap') -or
(Test-Path -LiteralPath '.\recovered.mcap')) {
throw 'Choose unused working and output paths.'
}
Copy-Item -LiteralPath '.\damaged.mcap' -Destination '.\working.mcap'
.\mcap.exe doctor .\working.mcap
.\mcap.exe recover .\working.mcap -o .\recovered.mcap --compression none
$recoveryExit = $LASTEXITCODE
Write-Output "Recovery exit code: $recoveryExit"
.\mcap.exe doctor .\recovered.mcap
.\mcap.exe info .\recovered.mcap
Save $LASTEXITCODE immediately after recover; another native command replaces it. Keep stderr as well as the exit code. A recovered output can be written while the tool reports a truncated record. If no usable output is produced, inspect that diagnostic rather than treating an existing filename as success.
The experiment used --compression none for small fixtures. The tested CLI also offers a preserve mode. Choose compression for your available disk space and downstream tools; the example is not a recommendation to expand a large mission log. Preserve the incident file and its hash so later analysis remains tied to the original input.
The same seven messages produced two different exit codes
We generated ten uncompressed, unchunked JSON messages on /example, with sequence numbers 0–9 and 0.1 seconds between messages. Python 3.12 created the fixtures, and the official Windows AMD64 executable reported mcap 0.3.0 (21755244b) mcap-rust/0.25.0. This was a synthetic container, not a ROS recording or robot playback test. The MCAP specification defines the record boundaries used for the cuts.
One copy ended immediately after the seventh complete message. Another ended inside the eighth message’s payload. The intact file was the control. All input hashes remained unchanged, and doctor accepted all recovered outputs.
| Input | doctor before recovery |
recover exit |
Decoded messages | Last sequence / time |
|---|---|---|---|---|
| Intact control | 0 | 0 | 10 | 9 / 1700000000.9 s |
| Cut at a record boundary after seven messages | 1 | 0 | 7 | 6 / 1700000000.6 s |
| Cut inside the eighth message | 1 | 3 | 7 | 6 / 1700000000.6 s |
The boundary-cut file is the important case: the scan found seven complete message records and returned 0 without knowing our fixture should contain ten. The other damaged input contained an incomplete record, which triggered a lossy-recovery warning and exit code 3. Its output was byte-for-byte identical to the boundary-cut recovery. Both were structurally readable subsets missing the last three expected messages.
For a real incident, compare the final recovered timestamp with the intended recording end or an independent end event. Sequence counters can help only when you know what that producer’s counter means; do not assume every topic uses a continuous sequence.
Count each required topic before using the log
Inspect the summary and, when the encoding is supported, the messages:
.\mcap.exe info .\recovered.mcap
.\mcap.exe cat .\recovered.mcap --json
cat --json was confirmed in the tested binary’s help and decoded our schemaless JSON. The online guide also shows --format=ndjson, which that binary’s help does not list. Use the option supported by your installed version. Real encodings can need schemas or application-specific readers; a decoding error is not evidence that zero messages survived.
For every topic needed by the analysis, check its count, first and last timestamps, large gaps and decodable payloads. A camera stream may survive while the transforms, calibration or operating-mode records needed to interpret it do not. Report those omissions with the usable time span, rather than labelling the entire recording complete.
Keep a compact note with the output: original and recovered hashes, CLI version and stderr, per-topic coverage, and the independent evidence for the expected end. The rosbag2 recording and playback guide covers preventing missing streams; the dataset lineage guide explains how to retain the relationship between an incident input and a derived dataset.
These three cases did not test compressed-chunk damage, missing schemas, arbitrary corruption, failing storage or ROS playback. They demonstrate why a readable recovery and a complete mission recording are separate conclusions. Sources and saved AI-assisted synthetic results were checked October 13, 2026.