dotnet/aspnetcore · error · InvalidOperationException

PersistentComponentState already initialized.

Error message

PersistentComponentState already initialized.

What it means

Thrown by PersistentComponentState.InitializeExistingState when called more than once. PersistentComponentState holds a single restoration table; re-initializing would either discard previously registered state or duplicate it. The framework calls this exactly once per render cycle; a second call indicates double initialization.

Solutions

  1. Do not call InitializeExistingState yourself - the framework owns its lifecycle.
  2. In tests, create a fresh PersistentComponentState per test rather than re-initializing one instance.
  3. If you build a custom host, ensure the prerender/restore path runs exactly once per circuit or page render.
  4. Check that middleware or an interceptor is not re-running the persistence pipeline.

Example fix

// before: reused state instance re-initialized each test
_state.InitializeExistingState(data, context); // throws on second test

// after: new instance per test, or clear first
_state = new PersistentComponentState(current, callbacks, restoringCallbacks);
_state.InitializeExistingState(data, context);
Defensive patterns

Strategy: validation

Validate before calling

// Framework owns this; in tests, build a fresh instance per test.
if (_stateAlreadyInitialized) throw new InvalidOperationException("PersistentComponentState already initialized.");

Try / catch

try { state.InitializeExistingState(data, context); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already initialized"))
{ /* create a new PersistentComponentState instead */ }

Prevention

When it happens

Trigger: The framework host (prerendering host, WebAssembly start, or a custom host) calls InitializeExistingState twice in one lifetime. In user code this is reached only if you manually drive PersistentComponentState in a custom hosting scenario or in a test that re-uses the same instance across renders.

Common situations: A test fixture that constructs PersistentComponentState once but initializes it per-test without resetting; a custom prerendering pipeline that runs twice; double-calling during a misconfigured prerender + interactive handoff.

Related errors


AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11). Data as JSON: /api/errors/0a068664a7ccfb0f. Report an issue: GitHub.

Appendix: source

Thrown at src/Components/Components/src/PersistentComponentState.cs:40

    internal PersistentComponentState(
        IDictionary<string, byte[]> currentState,
        List<PersistComponentStateRegistration> pauseCallbacks,
        List<RestoreComponentStateRegistration> restoringCallbacks)
    {
        _currentState = currentState;
        _registeredCallbacks = pauseCallbacks;
        _registeredRestoringCallbacks = restoringCallbacks;
    }

    internal bool PersistingState { get; set; }

    internal RestoreContext CurrentContext { get; private set; } = RestoreContext.InitialValue;

    internal void InitializeExistingState(IDictionary<string, byte[]> existingState, RestoreContext context)
    {
        if (_existingState != null)
        {
            throw new InvalidOperationException("PersistentComponentState already initialized.");
        }
        _existingState = existingState ?? throw new ArgumentNullException(nameof(existingState));
        CurrentContext = context;
    }

    /// <summary>
    /// Register a callback to persist the component state when the application is about to be paused.
    /// Registered callbacks can use this opportunity to persist their state so that it can be retrieved when the application resumes.
    /// </summary>
    /// <param name="callback">The callback to invoke when the application is being paused.</param>
    /// <returns>A subscription that can be used to unregister the callback when disposed.</returns>
    public PersistingComponentStateSubscription RegisterOnPersisting(Func<Task> callback)
        => RegisterOnPersisting(callback, null);

    /// <summary>
    /// Register a callback to persist the component state when the application is about to be paused.
    /// Registered callbacks can use this opportunity to persist their state so that it can be retrieved when the application resumes.
    /// </summary>

View on GitHub (pinned to 3600ca084e)