dotnet/aspnetcore · error · InvalidOperationException
The {nameof(ParameterView)} instance can no longer be read b
Error message
The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use. What it means
A ParameterView obtained during one render batch was read after the batch advanced (its validity stamp no longer matches the owning RenderBatchBuilder). ParameterView is a synchronous, snapshot-style struct; storing it across renders or async gaps and reading it later triggers this InvalidOperationException from ParameterViewLifetime.AssertNotExpired.
Source
Thrown at src/Components/Components/src/Rendering/ParameterViewLifetime.cs:25
{
private readonly RenderBatchBuilder _owner;
private readonly int _stamp;
public static readonly ParameterViewLifetime Unbound;
public ParameterViewLifetime(RenderBatchBuilder owner)
{
_owner = owner;
_stamp = owner.ParameterViewValidityStamp;
}
public void AssertNotExpired()
{
// If _owner is null, this instance is default(ParameterViewLifetime), which is
// the same as ParameterViewLifetime.Unbound. That means it never expires.
if (_owner != null && _owner.ParameterViewValidityStamp != _stamp)
{
throw new InvalidOperationException($"The {nameof(ParameterView)} instance can no longer be read because it has expired. {nameof(ParameterView)} can only be read synchronously and must not be stored for later use.");
}
}
}
View on GitHub (pinned to 3600ca084e)
Solutions
- Extract every value you need from ParameterView synchronously at the top of SetParametersAsync into local/field copies.
- Never store the ParameterView itself; if you must defer, copy into a Dictionary<string,object?> first.
- Re-fetch parameters via a fresh read in the next lifecycle call instead of reusing the snapshot.
Example fix
// before
public override async Task SetParametersAsync(ParameterView parameters)
{
_savedParams = parameters; // stored
await DoWork();
var x = _savedParams.GetValueOrDefault<int>("Count"); // expired!
}
// after
public override async Task SetParametersAsync(ParameterView parameters)
{
_count = parameters.GetValueOrDefault<int>("Count");
await DoWork();
} Defensive patterns
Strategy: validation
Validate before calling
// Always copy out values synchronously
public override Task SetParametersAsync(ParameterView parameters)
{
_count = parameters.GetValueOrDefault<int>(nameof(Count));
_name = parameters.GetValueOrDefault<string>(nameof(Name));
return base.SetParametersAsync(parameters);
} Prevention
- Never store ParameterView in a field.
- Extract all needed values at the top of SetParametersAsync before any await.
- If you must defer, copy into a Dictionary<string,object?> snapshot first.
When it happens
Trigger: Storing a ParameterView in a field and reading it in OnAfterRenderAsync, a timer callback, or after an await. Capturing `parameters` from SetParametersAsync into a Task and indexing it later. Passing ParameterView to another component/method that defers the read.
Common situations: Manually caching parameters for async work. Forgetting to copy needed values out of ParameterView at the top of SetParametersAsync. Component frameworks that try to forward ParameterView to children outside the synchronous scope.
Related errors
- There is no file with ID ${fileId}. The file list may have c
- initialParameters must be an object, even if empty.
- Dynamic root components have not been enabled in this applic
- Interop methods are already registered for renderer ${render
- Interop methods are not registered for renderer ${rendererId
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/67a815315e849c45.
Report an issue: GitHub.