{"record":{"id":"bf4dba6a50bf5325","repo":"dotnet/aspnetcore","slug":"state-already-persisted","errorCode":null,"errorMessage":"State already persisted.","messagePattern":"State already persisted\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs","lineNumber":104,"sourceCode":"        else\n        {\n            State.InitializeExistingState(data, context);\n            _servicesRegistry?.RegisterForPersistence(State);\n            _stateIsInitialized = true;\n        }\n    }\n\n    /// <summary>\n    /// Persists the component application state into the given <see cref=\"IPersistentComponentStateStore\"/>.\n    /// </summary>\n    /// <param name=\"store\">The <see cref=\"IPersistentComponentStateStore\"/> to restore the application state from.</param>\n    /// <param name=\"renderer\">The <see cref=\"Renderer\"/> that components are being rendered.</param>\n    /// <returns>A <see cref=\"Task\"/> that will complete when the state has been restored.</returns>\n    public Task PersistStateAsync(IPersistentComponentStateStore store, Renderer renderer)\n    {\n        if (_stateIsPersisted)\n        {\n            throw new InvalidOperationException(\"State already persisted.\");\n        }\n\n        return renderer.Dispatcher.InvokeAsync(PauseAndPersistState);\n\n        async Task PauseAndPersistState()\n        {\n            State.PersistingState = true;\n\n            if (store is IEnumerable<IPersistentComponentStateStore> compositeStore)\n            {\n                // We only need to do inference when there is more than one store. This is determined by\n                // the set of rendered components.\n                InferRenderModes(renderer);\n\n                // Iterate over each store and give it a chance to run against the existing declared\n                // render modes. After we've run through a store, we clear the current state so that\n                // the next store can start with a clean slate.\n                foreach (var store in compositeStore)","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs#L86-L122","documentation":"Thrown by ComponentStatePersistenceManager.PersistStateAsync when _stateIsPersisted is true. The flag is set at the end of PauseAndPersistState and never reset, so the manager is single-use for persistence within its lifetime.","triggerScenarios":"Calling PersistStateAsync(store, renderer) twice on the same manager instance.","commonSituations":"Middleware/endpoints invoking persist on each render without a fresh manager; tests reusing the manager; an integration that triggers persist both for prerender and for the final response.","solutions":["Persist once per manager/circuit lifetime; guard with your own flag.","Use a new ComponentStatePersistenceManager (new DI scope) for each persistence cycle if you need to persist again.","In hosted scenarios rely on the framework's single PersistStateAsync call during prerender rather than calling it yourself again.","Audit the request pipeline for duplicate persist invocations."],"exampleFix":"// before\nawait manager.PersistStateAsync(store, renderer); // called twice -> throws\n\n// after\nif (!_persisted)\n{\n    await manager.PersistStateAsync(store, renderer);\n    _persisted = true;\n}","handlingStrategy":"validation","validationCode":"private bool _persisted;\n\nasync Task PersistOnceAsync(ComponentStatePersistenceManager manager,\n    IPersistentComponentStateStore store, Renderer renderer)\n{\n    if (_persisted) return;\n    await manager.PersistStateAsync(store, renderer);\n    _persisted = true;\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    await manager.PersistStateAsync(store, renderer);\n}\ncatch (InvalidOperationException ex) when (ex.Message == \"State already persisted.\")\n{\n    // already persisted this cycle - nothing to do\n}","preventionTips":["Persist exactly once per manager/circuit lifetime; guard with a flag.","Rely on the framework's prerender persist call rather than calling PersistStateAsync yourself again.","Use a new manager/scope if a second persistence cycle is genuinely needed.","Audit the request pipeline for duplicate persist calls."],"tags":["blazor","component-state","persistence","lifecycle"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}