dotnet/aspnetcore · error · InvalidOperationException
Registering a callback while persisting state is not allowed
Error message
Registering a callback while persisting state is not allowed.
What it means
RegisterOnPersisting throws InvalidOperationException if called while PersistingState is true. Persisting callbacks can only be registered before the persistence phase begins; registering during persistence would never fire and indicates a logic error.
Source
Thrown at src/Components/Components/src/PersistentComponentState.cs:68
/// <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>
/// <param name="callback">The callback to invoke when the application is being paused.</param>
/// <param name="renderMode"></param>
/// <returns>A subscription that can be used to unregister the callback when disposed.</returns>
public PersistingComponentStateSubscription RegisterOnPersisting(Func<Task> callback, IComponentRenderMode? renderMode)
{
ArgumentNullException.ThrowIfNull(callback);
if (PersistingState)
{
throw new InvalidOperationException("Registering a callback while persisting state is not allowed.");
}
var persistenceCallback = new PersistComponentStateRegistration(callback, renderMode);
_registeredCallbacks.Add(persistenceCallback);
return new PersistingComponentStateSubscription(_registeredCallbacks, persistenceCallback);
}
/// <summary>
/// Register a callback to restore the state when the application state is being restored.
/// </summary>
/// <param name="callback"> The callback to invoke when the application state is being restored.</param>
/// <param name="options">Options that control the restoration behavior.</param>
/// <returns>A subscription that can be used to unregister the callback when disposed.</returns>
public RestoringComponentStateSubscription RegisterOnRestoring(Action callback, RestoreOptions options)
{
Debug.Assert(CurrentContext != null);View on GitHub (pinned to 294cab2f9b)
Solutions
- Register OnPersisting callbacks during OnInitialized (before persistence starts), not during it.
- Dispose the subscription when the component disposes to avoid duplicate registrations.
- Ensure components that need persistence are present before the persist phase begins.
Example fix
// before
protected override async Task OnPersistingAsync()
{
State.RegisterOnPersisting(ExtraPersist); // inside persist phase -> throws
}
// after
protected override void OnInitialized()
{
_sub = State.RegisterOnPersisting(Persist);
}
public void Dispose() => _sub?.Dispose(); Defensive patterns
Strategy: validation
Validate before calling
protected override void OnInitialized()
{
// Only register before persistence; never inside an OnPersisting callback
_persistSub = State.RegisterOnPersisting(PersistState);
}
private Task PersistState() { State.PersistAsJson("k", _data); return Task.CompletedTask; } Try / catch
try { _sub = State.RegisterOnPersisting(cb); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Registering a callback while persisting"))
{ logger.LogWarning(ex, "Too late to register OnPersisting"); } Prevention
- Always register OnPersisting callbacks in OnInitialized.
- Dispose subscriptions to avoid duplicate registrations.
- Mount persistence-dependent components before the persist phase.
When it happens
Trigger: Calling RegisterOnPersisting from inside another OnPersisting callback's execution; subscribing during the render that triggers persistence; late registration after the framework started serializing state.
Common situations: Components mounting late (during persistence) that try to register; dynamically added child components whose OnInitialized runs during the persist phase; re-registering on each render without disposing the prior subscription.
Related errors
- PersistentComponentState already initialized.
- Persisting state is only allowed during an OnPersisting call
- Interop methods are already registered for renderer ${render
- Interop methods are not registered for renderer ${rendererId
- No interop methods are registered for renderer ${rendererId}
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/5dfac554fb55d9f0.
Report an issue: GitHub.