dotnet/wpf · error · FileFormatException

SR.Format(SR.InvalidTransformFeatureName…

Error message

SR.Format(SR.InvalidTransformFeatureName, _fileVersion.FeatureIdentifier, _codeVersion.FeatureIdentifier)

What it means

EnsureParsed compares the feature identifier stored in the stream's version header against the identifier expected by the code's known version (_codeVersion). The comparison is case-insensitive; a mismatch means the stream belongs to a different transform, so a FileFormatException naming both identifiers is thrown.

Solutions

  1. Verify the file was produced by the same transform (check the two identifiers in the exception message).
  2. Regenerate or re-save the package with the correct tool/runtime version.
  3. Do not hand-edit the version header; restore the file from a trusted source.
  4. If supporting multiple transforms, route the stream to the correct VersionedStreamOwner based on the header identifier before parsing.

Example fix

// before: blindly opening any compound-file stream
var vs = new VersionedStreamOwner(stream, codeVersion);
vs.ReadAttempt(buffer, 0, len);
// after: pre-check the transform identity where possible, or catch and report
try { vs.ReadAttempt(buffer, 0, len); }
catch (FileFormatException e)
{ throw new InvalidDataException($"Stream transform mismatch: {e.Message}", e); }
Defensive patterns

Strategy: try-catch

Type guard

static bool SameTransform(string fileFeatureId, string codeFeatureId) =>
    string.Equals(fileFeatureId, codeFeatureId, StringComparison.OrdinalIgnoreCase);

Try / catch

try { owner.ReadAttempt(buffer, 0, len); }
catch (FileFormatException e) { throw new InvalidDataException($"Container transform mismatch: {e.Message}", e); }

Prevention

When it happens

Trigger: Opening a compound-file stream whose serialized version header carries a FeatureIdentifier that does not (case-insensitively) equal the transform's expected FeatureIdentifier, during ReadAttempt/WriteAttempt/IsReadable/IsUpdatable.

Common situations: Files produced by a different compression/transform implementation or a different product version; corrupted or renamed header fields; opening a non-XPS compound file that coincidentally has a version block.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/ff441ccd0a5dff74. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/CompoundFile/VersionedStreamOwner.cs:400

                // which the stream belongs. The "logical" stream object handed to us by the
                // compound file begins -after- this stream header, so when we seek to the
                // "beginning" of this stream, we are actually seeking to the location after
                // the stream header, where the instance data starts.
                //
                BaseStream.Seek(0, SeekOrigin.Begin);

                //
                // The instance data starts with format version information for this transform.
                //
                _fileVersion = FormatVersion.LoadFromStream(BaseStream);

                //
                // Ensure that the feature name is as expected.
                //
                // NOTE: We preserve case, but do case-insensitive comparison.
                if (!string.Equals(_fileVersion.FeatureIdentifier, _codeVersion.FeatureIdentifier, StringComparison.OrdinalIgnoreCase))
                {
                    throw new FileFormatException(
                                    SR.Format(
                                        SR.InvalidTransformFeatureName,
                                        _fileVersion.FeatureIdentifier,
                                        _codeVersion.FeatureIdentifier
                                        )
                                    );
                }

                _dataOffset = BaseStream.Position;
            }
        }

        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
        private bool            _writeOccurred;     // did one of our streams get written to?

View on GitHub (pinned to 81131a70a4)