dotnet/aspnetcore · error · InvalidOperationException
Persisting state is only allowed during an OnPersisting call
Error message
Persisting state is only allowed during an OnPersisting callback.
What it means
PersistAsJson<T> (public generic) throws InvalidOperationException when PersistingState is false. State may only be written during an OnPersisting callback, which the framework gates by setting PersistingState=true; calling PersistAsJson from arbitrary code is rejected.
Source
Thrown at src/Components/Components/src/PersistentComponentState.cs:115
}
return default;
}
/// <summary>
/// Serializes <paramref name="instance"/> as JSON and persists it under the given <paramref name="key"/>.
/// </summary>
/// <typeparam name="TValue">The <paramref name="instance"/> type.</typeparam>
/// <param name="key">The key to use to persist the state.</param>
/// <param name="instance">The instance to persist.</param>
[RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
public void PersistAsJson<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string key, TValue instance)
{
ArgumentNullException.ThrowIfNull(key);
if (!PersistingState)
{
throw new InvalidOperationException("Persisting state is only allowed during an OnPersisting callback.");
}
if (!_currentState.TryAdd(key, JsonSerializer.SerializeToUtf8Bytes(instance, JsonSerializerOptionsProvider.Options)))
{
throw new ArgumentException($"There is already a persisted object under the same key '{key}'");
}
}
[RequiresUnreferencedCode("JSON serialization and deserialization might require types that cannot be statically analyzed.")]
internal void PersistAsJson(string key, object instance, [DynamicallyAccessedMembers(JsonSerialized)] Type type)
{
ArgumentNullException.ThrowIfNull(key);
if (!PersistingState)
{
throw new InvalidOperationException("Persisting state is only allowed during an OnPersisting callback.");
}
View on GitHub (pinned to 294cab2f9b)
Solutions
- Move the PersistAsJson call inside a method registered via RegisterOnPersisting (the OnPersisting callback).
- Verify the subscription is created in OnInitialized so the callback actually runs.
- Do not call PersistAsJson from constructors, render, or event handlers.
Example fix
// before
protected override void OnInitialized()
{
State.PersistAsJson("cart", _cart); // outside persist phase -> throws
}
// after
protected override void OnInitialized()
{
State.RegisterOnPersisting(() => { State.PersistAsJson("cart", _cart); return Task.CompletedTask; });
} Defensive patterns
Strategy: validation
Validate before calling
protected override void OnInitialized()
{
State.RegisterOnPersisting(Persist);
}
private Task Persist()
{
// PersistingState is true here; safe to persist
State.PersistAsJson("app.state", _data);
return Task.CompletedTask;
} Try / catch
try { State.PersistAsJson(key, value); }
catch (InvalidOperationException ex) when (ex.Message.Contains("only allowed during an OnPersisting callback"))
{ logger.LogError(ex, "PersistAsJson called outside persist phase"); } Prevention
- Only call PersistAsJson from within an OnPersisting callback.
- Verify the callback registration happened in OnInitialized.
- Avoid persisting from event handlers or render methods.
When it happens
Trigger: Calling State.PersistAsJson(...) from OnInitialized, OnAfterRender, an event handler, or any non-persisting context; calling it after the persist phase has ended.
Common situations: Developers assuming state can be persisted at any time; refactoring persistence logic out of the OnPersisting callback; timing issues where the callback registration did not run.
Related errors
- JS object instance with Id '${id}' does not exist. It may ha
- PersistentComponentState already initialized.
- Registering a callback while persisting state is not allowed
- Interop methods are already registered for renderer ${render
- Interop methods are not registered for renderer ${rendererId
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/7cfa7eee05317713.
Report an issue: GitHub.