dotnet/wpf · error · InvalidOperationException

SR.Image_MetadataReadOnly

Error message

SR.Image_MetadataReadOnly

What it means

Thrown from BitmapMetadata.SetQuery (and similar write paths) when the metadata object was opened in read-only mode (_readOnly == true). WPF marks metadata read-only when it comes from a read-only source, such as a BitmapFrame decoded from a stream not opened for writing or metadata obtained from a frozen frame. Writing a query to such metadata is an invalid operation, so the library refuses it up front.

Solutions

  1. Obtain a writable BitmapMetadata: decode with write access (e.g., create metadata via new BitmapMetadata("jpeg") and set it on the encoder) rather than mutating decoder-supplied metadata.
  2. Check IsReadOnly (or IsFrozen) before calling SetQuery and clone the metadata into a new writable BitmapMetadata if needed.
  3. Use BitmapEncoder with InPlaceBitmapMetadataWriter for in-place edits on file streams opened for writing.
  4. Wrap SetQuery in try/catch for InvalidOperationException and surface that the metadata source is read-only.

Example fix

// before
var meta = frame.Metadata as BitmapMetadata;
meta.SetQuery("/app1/ifd/exif/{ushort=271}", "Canon"); // throws: read-only
// after
var meta = new BitmapMetadata("jpeg");
meta.SetQuery("/app1/ifd/exif/{ushort=271}", "Canon");
encoder.Frames.Add(BitmapFrame.Create(source, frame.Thumbnail, meta, frame.ColorContexts));
Defensive patterns

Strategy: validation

Validate before calling

if (meta == null) throw new ArgumentNullException(nameof(meta));
if (meta.IsReadOnly || meta.IsFrozen)
    meta = new BitmapMetadata("jpeg") { /* copy fields */ };

Type guard

static bool IsWritable(BitmapMetadata meta) => meta != null && !meta.IsReadOnly && !meta.IsFrozen;

Try / catch

try { meta.SetQuery(query, value); }
catch (InvalidOperationException) { meta = CloneWritable(meta); meta.SetQuery(query, value); }

Prevention

When it happens

Trigger: Calling BitmapMetadata.SetQuery(query, value) on a BitmapMetadata whose _readOnly flag is set — typically metadata retrieved from a frame of an image decoded without write access (e.g., BitmapCreateOptions or reading from a non-writable stream), or metadata from a frozen bitmap.

Common situations: Trying to embed EXIF/IPTC/XMP tags into a JPEG loaded from a web stream or Resource; reading metadata with a decoder and then attempting SetQuery on it; sharing one BitmapMetadata between a read-only frame and an intended-write encoder.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/Media/Imaging/BitmapMetadata.cs:1018

        #endregion

        #region Query Methods

        /// <summary>
        ///
        /// </summary>
        public void SetQuery(String query, object value)
        {
            WritePreamble();

            ArgumentNullException.ThrowIfNull(query);

            ArgumentNullException.ThrowIfNull(value);

            if (_readOnly)
            {
                throw new System.InvalidOperationException(SR.Image_MetadataReadOnly);
            }

            // Store these for debugging stress failures.
            _setQueryString = query;
            _setQueryValue = value;

            EnsureBitmapMetadata();

            PROPVARIANT propVar = new PROPVARIANT();

            try
            {
                propVar.Init(value);

                if (propVar.RequiresSyncObject)
                {
                    BitmapMetadata metadata = value as BitmapMetadata;
                    Invariant.Assert(metadata != null);

View on GitHub (pinned to 81131a70a4)