A versioning scheme that encodes much of the needed information directly is great for this.
An example:
X.Y.Z-[Dialect/Version]
X - Major version changes, can not be expected to read streams of previous versions correctly (changed storage format for something)
Y - Minor version changes, can be expected to read older versions, but not newer, correctly (added new capabilities to the format, such as new hooks etc.)
Z - Internal changes/bugfixes, (no changes to the actual serialization format)
[Dialect/Version] - Not needed for error recovery if classes of serialized instances are included, as that is better to use directly if encountering missing/incompatible definitions, but a nice bit of info to start from otherwise...
Cheers,
Henry