dotnet/wpf · error · InvalidOperationException

SR.ThreadAlreadyStarted

Error message

SR.ThreadAlreadyStarted

What it means

XamlBackgroundReader.StartThread starts a single background read thread; if _thread is already created it throws InvalidOperationException(SR.ThreadAlreadyStarted). Each reader instance may only start its background thread once.

Solutions

  1. Call StartThread exactly once per reader instance; create a new XamlBackgroundReader for a fresh read cycle.
  2. Guard the call: only invoke StartThread when the thread has not been started yet.
  3. Move StartThread to a single construction/initialization point rather than call sites scattered across code.
  4. Catch InvalidOperationException for ThreadAlreadyStarted if double-start is possible in your flow.

Example fix

// before
reader.StartThread("xaml");
reader.StartThread("xaml-retry"); // throws
// after
if (readerStarted) reader = new XamlBackgroundReader(...);
reader.StartThread("xaml");
readerStarted = true;
Defensive patterns

Strategy: validation

Validate before calling

if (readerThreadStarted) throw new InvalidOperationException("StartThread already called on this XamlBackgroundReader.");
reader.StartThread("xaml");
readerThreadStarted = true;

Try / catch

try { reader.StartThread(name); } catch (InvalidOperationException ex) when (/* ThreadAlreadyStarted */) { /* reuse existing thread or recreate reader */ }

Prevention

When it happens

Trigger: Calling StartThread(name) twice on the same XamlBackgroundReader instance, e.g. calling it manually after the reader already auto-started, or calling it again after a prior successful start in retry logic.

Common situations: Re-initializing a reader that was reused across parse runs; wrapper layers and unit helpers both calling StartThread; code that retries StartThread after an unrelated failure assuming the thread never launched.

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

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/XamlBackgroundReader.cs:87

                xamlNodeNextDelegate = new XamlNodeNextDelegate(Next);
            }

            _internalReader = new ReaderDelegate(_wrappedReader.SchemaContext, xamlNodeNextDelegate, _wrappedReaderHasLineInfo);

            // Standin so it won't start null
            _currentNode = new XamlNode(XamlNode.InternalNodeType.StartOfStream);
        }

        public void StartThread()
        {
            StartThread("XAML reader thread");
        }

        public void StartThread(string threadName)
        {
            if (_thread is not null)
            {
                throw new InvalidOperationException(SR.ThreadAlreadyStarted);
            }

            ParameterizedThreadStart start = new ParameterizedThreadStart(XamlReaderThreadStart);
            _thread = new Thread(start)
            {
                Name = threadName
            };
            _thread.Start();
        }

        // The "ThreadStart" function
        private void XamlReaderThreadStart(object none)
        {
            try
            {
                InterruptableTransform(_wrappedReader, _writer, true);
            }
            catch (Exception ex)

View on GitHub (pinned to 81131a70a4)