dotnet/wpf · error · InvalidOperationException

SR.BamlWriterBadScope

Error message

SR.BamlWriterBadScope: {0} {1}

What it means

WriteEndComplexProperty inspects the start-tag type of the currently open complex property and writes the matching end record. If the start tag is not a PropertyComplexStart (default case in its switch), it throws InvalidOperationException(SR.BamlWriterBadScope, startTagType, PropertyComplexEnd), indicating the end call does not match the open scope. This guards against mismatched push/pop of BAML records.

Solutions

  1. Call the matching End method: WriteEndArrayProperty, WriteEndIListProperty, or WriteEndIDictionaryProperty for their respective Start calls.
  2. Keep a stack of started scope types and pop with the exact matching End call.
  3. Fix ordering so element starts are closed with WriteEndElement, not WriteEndComplexProperty.

Example fix

// before
writer.WriteStartIListProperty("Children");
writer.WriteEndComplexProperty(); // mismatch
// after
writer.WriteStartIListProperty("Children");
writer.WriteEndIListProperty();
Defensive patterns

Strategy: validation

Validate before calling

var scopeStack = new Stack<BamlRecordType>();
void EndScope(BamlWriter w)
{
    var start = scopeStack.Peek();
    if (start == BamlRecordType.PropertyComplexStart) w.WriteEndComplexProperty();
    else if (start == BamlRecordType.PropertyArrayStart) w.WriteEndArrayProperty();
    else if (start == BamlRecordType.PropertyIListStart) w.WriteEndIListProperty();
    else if (start == BamlRecordType.PropertyIDictionaryStart) w.WriteEndIDictionaryProperty();
    scopeStack.Pop();
}

Try / catch

try { writer.WriteEndComplexProperty(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("BamlWriterBadScope") || ex.Message.Contains("Property"))
{
    // unwind scopes in a finally/stack-based manner instead
}

Prevention

When it happens

Trigger: Calling WriteEndComplexProperty when the open scope was actually started by an array start, IList start, IDictionary start, or element start — i.e. the wrong End method for the scope.

Common situations: Using WriteEndComplexProperty to close WriteStartArrayProperty/WriteStartIListProperty/WriteStartIDictionaryProperty scopes in a custom serializer; copy-pasted end calls in a state machine; exception unwinding that skipped the matching End call.

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/9033b919075c3600. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/BamlWriter.cs:794

                    XamlPropertyIDictionaryEndNode dictionaryEnd = 
                                      new XamlPropertyIDictionaryEndNode(
                                                  0, 
                                                  0, 
                                                  --_depth);
                    _bamlRecordWriter.WritePropertyIDictionaryEnd(dictionaryEnd);
                    break;
                    
                case BamlRecordType.PropertyComplexStart:
                    XamlPropertyComplexEndNode complexEnd = 
                                       new XamlPropertyComplexEndNode(
                                                  0, 
                                                  0, 
                                                  --_depth);
                    _bamlRecordWriter.WritePropertyComplexEnd(complexEnd);
                    break;

                default:
                    throw new InvalidOperationException(
                                    SR.Format(SR.BamlWriterBadScope,
                                           startTagType.ToString(),
                                           BamlRecordType.PropertyComplexEnd.ToString()));
            }                        
            _parserContext.PopScope();
        }

        /// <summary>
        /// Write a literal content record to baml stream
        /// </summary>
        public void WriteLiteralContent(
            string contents)
        {
            VerifyWriteState();
            ProcessMarkupExtensionNodes();

            XamlLiteralContentNode literalContent = new XamlLiteralContentNode(
                                                               0,

View on GitHub (pinned to 81131a70a4)