{"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/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Components/src/PersistentState/ComponentStatePersistenceManager.cs#L86-L122","documentation":"ComponentStatePersistenceManager.PersistStateAsync enforces a single-persistence contract via the _stateIsPersisted flag. Once PersistStateAsync has completed (the flag is set true at the end of PauseAndPersistState), a second call throws. Persistence is a destructive, terminal operation: it pauses state, drains registered callbacks into _currentState, writes to the store, and clears working buffers, so repeating it would produce partial or empty output.","triggerScenarios":"Calling PersistStateAsync(store, renderer) twice on the same manager instance. A host/endpoint pipeline that runs the persist step more than once for a single render (e.g., both a response-writing middleware and a developer's manual call). Persisting after a composite-store persistence loop already completed.","commonSituations":"Adding custom middleware that also persists component state alongside the framework's built-in persistence. Endpoints that render and persist, then a fallback path re-invokes persistence on exception handling. Integration tests that reuse a manager across multiple render-then-persist cycles.","solutions":["Ensure PersistStateAsync is invoked exactly once per manager lifetime; track persistence state in your host code if multiple paths could reach it.","For repeated persistence (e.g., tests), create a new ComponentStatePersistenceManager for each cycle.","Audit middleware/endpoint order so only the framework-owned persistence hook calls PersistStateAsync."],"exampleFix":"// before: persisted twice\nawait manager.PersistStateAsync(store, renderer);\nawait manager.PersistStateAsync(store, renderer); // throws\n\n// after: single persistence, or new manager per cycle\nawait manager.PersistStateAsync(store, renderer);\n// for a new cycle, construct a fresh manager","handlingStrategy":"validation","validationCode":"if (!_persisted)\n{\n    await manager.PersistStateAsync(store, renderer);\n    _persisted = true;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Invoke PersistStateAsync exactly once per render lifecycle.","Audit middleware/endpoint order so only one path persists.","In integration tests, create a new manager for each persist cycle."],"tags":["blazor","persistent-state","persistence","lifecycle"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}