{"record":{"id":"3d8b1a39b88c27ed","repo":"dotnet/aspnetcore","slug":"cannot-update-existing-state-previous-state-has-n","errorCode":null,"errorMessage":"Cannot update existing state: previous state has not been cleared or state is not initialized.","messagePattern":"Cannot update existing state: previous state has not been cleared or state is not initialized\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Components/Components/src/PersistentComponentState.cs","lineNumber":249,"sourceCode":"\n        if (_existingState.TryGetValue(key, out value))\n        {\n            _existingState.Remove(key);\n            return true;\n        }\n        else\n        {\n            return false;\n        }\n    }\n\n    internal void UpdateExistingState(IDictionary<string, byte[]> state, RestoreContext context)\n    {\n        ArgumentNullException.ThrowIfNull(state);\n\n        if (_existingState == null || _existingState.Count > 0)\n        {\n            throw new InvalidOperationException(\"Cannot update existing state: previous state has not been cleared or state is not initialized.\");\n        }\n\n        _existingState = state;\n        CurrentContext = context;\n    }\n}\n","sourceCodeStart":231,"sourceCodeEnd":256,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Components/src/PersistentComponentState.cs#L231-L256","documentation":"PersistentComponentState.UpdateExistingState is an internal method invoked during state restoration with RestoreContext.ValueUpdate. It refuses to install new state when the existing state dictionary is null (never initialized via InitializeExistingState) or still contains unconsumed entries (Count > 0). The guard prevents silently discarding or merging leftover persisted entries, which would corrupt the restore contract that expects each key to be consumed exactly once via TryTake.","triggerScenarios":"RestoreStateAsync(store, RestoreContext.ValueUpdate) is called before any prior RestoreStateAsync(store, RestoreContext.InitialValue) ran (so _existingState is still null), or it is called while previously-restored entries have not yet been consumed via PersistentComponentState.TryTake/TryTakeBytes. Calling UpdateExistingState directly with a non-empty current state also triggers it.","commonSituations":"A custom IPersistentComponentStateStore or host pipeline that drives a second restore pass for value updates without first performing the initial restore. Persisting a value provider subscription whose restoring callback re-enters RestoreStateAsync while prior keys remain unconsumed. Misordered startup hooks in a Blazor Web App that interleave prerender restore and interactive restore incorrectly.","solutions":["Ensure RestoreStateAsync(store, RestoreContext.InitialValue) runs to completion exactly once before any RestoreContext.ValueUpdate restore so _existingState becomes non-null.","Consume or clear all entries from the current state (every registered restoring callback must call TryTake for its keys) before invoking a ValueUpdate restore.","If you hold a reference to PersistentComponentState, verify State exists and drain it before the update; do not call the internal UpdateExistingState directly."],"exampleFix":"// before: second restore with ValueUpdate before initial restore finished\nawait manager.RestoreStateAsync(store, RestoreContext.ValueUpdate);\n\n// after: initialize first, then update only when prior state is drained\nawait manager.RestoreStateAsync(store, RestoreContext.InitialValue);\n// ... components consume their keys via TryTake ...\nawait manager.RestoreStateAsync(store, RestoreContext.ValueUpdate);","handlingStrategy":"validation","validationCode":"// Validate before triggering a ValueUpdate restore.\n// Ensure initial restore ran and existing state is empty.\nif (!stateInitialized)\n{\n    await manager.RestoreStateAsync(store, RestoreContext.InitialValue);\n}\n// Drain prior keys before the update pass\nforeach (var key in requiredKeys)\n{\n    state.TryTake(key, out _);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always run the initial restore exactly once before any ValueUpdate restore.","Ensure every restoring callback consumes its keys via TryTake before requesting an update.","Treat PersistentComponentState as single-consumption: each persisted key is removed when read."],"tags":["blazor","persistent-state","restore","lifecycle"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}