dotnet/aspnetcore · error · InvalidOperationException
Cannot update existing state: previous state has not been cl
Error message
Cannot update existing state: previous state has not been cleared or state is not initialized.
What it means
Thrown by PersistentComponentState.UpdateExistingState when _existingState is null (state was never initialized via InitializeExistingState) OR when _existingState.Count > 0 (previously restored entries were never consumed via TryTake). UpdateExistingState is called from RestoreStateAsync only when the context is RestoreContext.ValueUpdate, i.e. during an in-place value update rather than the initial restore.
Source
Thrown at src/Components/Components/src/PersistentComponentState.cs:249
if (_existingState.TryGetValue(key, out value))
{
_existingState.Remove(key);
return true;
}
else
{
return false;
}
}
internal void UpdateExistingState(IDictionary<string, byte[]> state, RestoreContext context)
{
ArgumentNullException.ThrowIfNull(state);
if (_existingState == null || _existingState.Count > 0)
{
throw new InvalidOperationException("Cannot update existing state: previous state has not been cleared or state is not initialized.");
}
_existingState = state;
CurrentContext = context;
}
}
View on GitHub (pinned to 294cab2f9b)
Solutions
- Ensure the initial RestoreStateAsync(store) (default RestoreContext.InitialValue) runs exactly once before any RestoreContext.ValueUpdate restore.
- Make sure every persisted key is consumed (TryTake*) on each cycle so _existingState is empty before the next update.
- If some keys must survive across updates, restructure the store to return a fresh dictionary for value updates instead of relying on leftover entries.
- Audit restoring callbacks to confirm they all call TryTakeFromJson/TryTakeBytes for their keys.
Example fix
// before: restoring callback registered but never consumes its key
state.RegisterOnRestoring(() => { /* reads _local, never calls TryTake */ });
// after: consume the key on every restore
state.RegisterOnRestoring(() =>
{
if (state.TryTakeFromJson<Cart>("cart", out var restored))
_local = restored;
}); Defensive patterns
Strategy: validation
Validate before calling
// In a custom store/host: ensure the initial restore ran and prior state was consumed
// before issuing a ValueUpdate restore.
bool CanValueUpdate(ComponentStatePersistenceManager m)
=> m.State.CurrentContext != RestoreContext.InitialValue; // simplistic gate
// Stronger: ensure your restoring callbacks always consume their keys so existingState empties. Try / catch
try
{
await manager.RestoreStateAsync(store, RestoreContext.ValueUpdate);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("Cannot update existing state"))
{
// state never initialized or not fully consumed - reinitialize instead
await manager.RestoreStateAsync(store); // fresh initial restore
} Prevention
- Always run the initial RestoreStateAsync(store) once before any ValueUpdate restore.
- Make every restoring callback consume its key via TryTakeFromJson/TryTakeBytes on each cycle.
- Audit your persistent service/component restoring callbacks for keys they never consume.
- Return a fresh empty dictionary from your store on value updates if keys need not survive.
When it happens
Trigger: Calling RestoreStateAsync(store, RestoreContext.ValueUpdate) before the initial RestoreStateAsync(store) has run; or after a restore where some persisted keys were never consumed by TryTakeFromJson/TryTakeBytes, leaving _existingState non-empty when the next ValueUpdate arrives.
Common situations: A custom IPersistentComponentStateStore or host that drives multiple restore cycles (e.g. streaming updates) but skips the initial restore; a persistent service/component that registers a restoring callback but does not consume its key on update; partial consumption of state across value-update cycles.
Related errors
- State already initialized.
- State already persisted.
- The registered callback {registration.Callback.Method.Name}
- The type '{targetType.FullName}' declares a property matchin
- A public property '{propertyName}' on component type '{type.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/3d8b1a39b88c27ed.
Report an issue: GitHub.