dotnet/wpf · error · XpsPackagingException

Only writers can call this method.

Error message

Only writers can call this method.

What it means

XpsManager.GeneratePart refuses to run when the XpsManager was not opened in writer mode. Only the instance designated as the package writer may add parts to the XPS package; all other instances (readers) throw XpsPackagingException with SR.ReachPackaging_OnlyWriters. This enforces single-writer access to the underlying Package.

Solutions

  1. Open the XpsDocument/XpsManager in write mode so IsWriter is true (pass true for the writer/editable argument when constructing the XpsDocument).
  2. Check xpsManager.IsWriter before calling GeneratePart and route write operations to the instance that owns write access.
  3. Ensure the underlying file/stream is writable; open a new writable stream if the source was read-only.
  4. Verify only one writer instance exists and write calls are not accidentally made on a reader obtained from GetXpsDocument/Packaging conversions.

Example fix

// before
var doc = new XpsDocument(pkgPath, FileAccess.Read);
var part = xpsManager.GeneratePart(partUri, contentType, compressionOption);
// after
var doc = new XpsDocument(pkgPath, FileAccess.ReadWrite);
if (!xpsManager.IsWriter) throw new InvalidOperationException("This XpsManager is read-only");
var part = xpsManager.GeneratePart(partUri, contentType, compressionOption);
Defensive patterns

Strategy: validation

Validate before calling

if (xpsManager == null || xpsManager.IsDisposed) throw new ObjectDisposedException(nameof(xpsManager));
if (!xpsManager.IsWriter) throw new InvalidOperationException("GeneratePart requires an XpsManager opened in writer mode.");

Type guard

bool CanWrite(XpsManager m) => m is { IsWriter: true };

Try / catch

try { var part = xpsManager.GeneratePart(partUri, contentType, compressionOption); }
catch (XpsPackagingException ex) when (ex.Message.Contains("writers")) { /* route to writer instance or reopen writable */ }

Prevention

When it happens

Trigger: Calling GeneratePart on an XpsManager whose IsWriter property is false — i.e. an XpsDocument opened with the writer parameter false or obtained for read-only access — while trying to add a part with a given partUri and contentType.

Common situations: Opening an XpsDocument for read access (e.g. to inspect fixed documents) and then attempting to add resources or parts; sharing one package between a reader and expecting it to also write; opening the document from a read-only file/stream so the writer flag could not be set.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/ReachFramework/Packaging/XpsManager.cs:295

        #endregion Public properties

        #region Public methods
        /// <summary>
        /// Generate a unique Part for the content type and add it to the package.
        /// Adding to any relationships or selector/sequence markup is not done.
        /// </summary>
        public
        PackagePart
        GeneratePart(
            ContentType contentType,
            Uri      	partUri
            )
       {
            ObjectDisposedException.ThrowIf(_metroPackage is null, typeof(XpsManager));
            if (!IsWriter)
            {
                throw new XpsPackagingException(SR.ReachPackaging_OnlyWriters);
            }
            ArgumentNullException.ThrowIfNull(contentType);
            if (0 == contentType.ToString().Length)
            {
                throw new ArgumentException(SR.Format(SR.ReachPackaging_InvalidContentType, contentType), nameof(contentType));
            }
            
            //Do not compress image Content Types
            CompressionOption compressionOption = _compressionOption;

            if (contentType.AreTypeAndSubTypeEqual(XpsS0Markup.JpgContentType) ||
                contentType.AreTypeAndSubTypeEqual(XpsS0Markup.PngContentType) ||
                contentType.AreTypeAndSubTypeEqual(XpsS0Markup.TifContentType) ||
                contentType.AreTypeAndSubTypeEqual(XpsS0Markup.WdpContentType))
            {
                compressionOption = CompressionOption.NotCompressed;
            }

View on GitHub (pinned to 81131a70a4)