dotnet/wpf · error · XamlObjectWriterException

SR.CannotSetBaseUri

Error message

SR.CannotSetBaseUri

What it means

XamlObjectWriterException thrown by Logic_CheckBaseUri when a BaseUri property assignment is attempted either after BaseUri was already set or on a non-root element (context depth greater than 2). BaseUri may only be assigned once, on the root element of the XAML stream.

Solutions

  1. Strip duplicate BaseUri/xml:base declarations from non-root elements before writing the node stream.
  2. Set BaseUri exactly once, only for the root object (Depth <= 2 in the writer).
  3. If merging documents, keep only the outermost document's base URI and drop inner ones.
  4. Guard the write site: check ctx.BaseUri is null and ctx.Depth <= 2 before emitting the BaseUri member.

Example fix

// before
WriteBaseUri(childObject, "file:///merged.xaml"); // non-root: throws
// after
if (ctx.BaseUri == null && ctx.Depth <= 2)
    WriteBaseUri(rootObject, "file:///merged.xaml");
// else skip — nested fragments inherit the root base URI
Defensive patterns

Strategy: validation

Validate before calling

if (ctx.BaseUri != null || ctx.Depth > 2)
    return; // skip: BaseUri already set or not on root element

Type guard

static bool CanSetBaseUri(ObjectWriterContext ctx) => ctx.BaseUri == null && ctx.Depth <= 2;

Try / catch

try { WriteBaseUri(obj, uri); }
catch (XamlObjectWriterException ex) when (ex.Message == System.Xaml.SR.CannotSetBaseUri) { LogDuplicateBaseUri(uri); }

Prevention

When it happens

Trigger: Writing a second xml:base / BaseUri value into the node stream, or assigning BaseUri while the object writer sits deeper than the root element (Depth > 2, i.e. past the root's StartObject/StartMember slots).

Common situations: Merging or concatenating XAML fragments that each declare xml:base; templates/includes that re-declare base URI inside nested elements; custom node-stream transformers duplicating the BaseUri member on child objects.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/XamlObjectWriter.cs:1669

                else if (prop == XamlLanguage.Base)
                {
                    Logic_CheckBaseUri(ctx, (string)value);
                    ctx.BaseUri = new Uri((string)value);
                    if (ctx.ParentInstance is not null)
                    {
                        Runtime.SetUriBase(ctx.ParentType, ctx.ParentInstance, ctx.BaseUri);
                    }
                }
            }
        }

        private void Logic_CheckBaseUri(ObjectWriterContext ctx, string value)
        {
            // Make sure BaseUri is not already set and that we can only set BaseUri on the root element
            // Depth > 2 because on the root element, SO/SM takes 1 slot, V is slot 2
            if ((ctx.BaseUri is not null) || (ctx.Depth > 2))
            {
                throw new XamlObjectWriterException(SR.CannotSetBaseUri);
            }
        }

        /// <summary>
        /// Process the call to a MarkupExtension.ProvideValue() and assign the result
        /// </summary>
        private void Logic_AssignProvidedValue(ObjectWriterContext ctx)
        {
            bool handled = Logic_ProvideValue(ctx);
            if (!handled && ctx.ParentProperty is not null)
            {
                Logic_DoAssignmentToParentProperty(ctx);
            }
        }

        // Returns true if the assignment was handled by a SetMarkupExtensionHandler
        private bool Logic_ProvideValue(ObjectWriterContext ctx)
        {

View on GitHub (pinned to 81131a70a4)