dotnet/aspnetcore · error
Unexpected renderer ID '${rendererId}' encountered while dis
Error message
Unexpected renderer ID '${rendererId}' encountered while discovering new state. What it means
Thrown in refreshRootComponents() at WebRootComponentManager.ts:324 while iterating rendererIds collected from persisted-state discovery. The loop only knows how to discover state for WebRendererId.Server and WebRendererId.WebAssembly; any other numeric rendererId means the enum gained a value the JS client does not understand, so it refuses rather than silently dropping persisted state for unknown renderers.
Source
Thrown at src/Components/Web.JS/src/Services/WebRootComponentManager.ts:324
// and if there are no updates on this batch, push an empty set of operations
// to ensure we send the state over. Same for wasm below.
serverState = discoverServerPersistedState(document) || '';
if (serverState && serverState !== '') {
const ops = operationsByRendererId.get(WebRendererId.Server);
if (!ops) {
operationsByRendererId.set(WebRendererId.Server, []);
}
}
} else if (rendererId === WebRendererId.WebAssembly) {
webAssemblyState = discoverWebAssemblyPersistedState(document) || '';
if (webAssemblyState && webAssemblyState !== '') {
const ops = operationsByRendererId.get(WebRendererId.WebAssembly);
if (!ops) {
operationsByRendererId.set(WebRendererId.WebAssembly, []);
}
}
} else {
throw new Error(`Unexpected renderer ID '${rendererId}' encountered while discovering new state.`);
}
}
}
for (const [rendererId, operations] of operationsByRendererId) {
const batch: RootComponentOperationBatch = {
batchId: this._nextOperationBatchId++,
operations,
};
this._pendingOperationBatches[batch.batchId] = batch;
const batchJson = JSON.stringify(batch);
if (rendererId === WebRendererId.Server) {
updateServerRootComponents(batchJson, serverState);
} else {
this.updateWebAssemblyRootComponents(batchJson, webAssemblyState);
}
}View on GitHub (pinned to 294cab2f9b)
Solutions
- Clear cached browser assets and republish so blazor.web.js matches the server runtime version exactly.
- Ensure the JS bundle is rebuilt whenever the server-side Blazor runtime is updated (run npm run build / publish the client assets together).
- If you added a custom rendermode, verify it maps to a known WebRendererId rather than an arbitrary integer.
- Check for stale CDN-cached blazor.web.js and bust the cache.
Defensive patterns
Strategy: validation
Validate before calling
import { WebRendererId } from '../Rendering/WebRendererId';
function isKnownRendererId(id: number): boolean {
return id === WebRendererId.Server || id === WebRendererId.WebAssembly;
} Type guard
function isKnownWebRendererId(id: unknown): id is WebRendererId {
return id === WebRendererId.Server || id === WebRendererId.WebAssembly;
} Prevention
- Always rebuild and republish blazor.web.js alongside server runtime updates.
- Bust CDN/browser cache of the JS bundle after upgrades.
- Map custom rendermodes only to known WebRendererId values.
- Run integration tests that assert Server/WebAssembly state discovery works across upgrades.
When it happens
Trigger: A component's assignedRendererId is set to a value outside {Server, WebAssembly} (per the WebRendererId enum known to this JS client), and discoverNewState=true. The else branch of the Server/WebAssembly check fires.
Common situations: Version skew between the .NET server runtime (which may assign a new renderer enum value) and the shipped blazor.web.js (which only knows the old enum). Mixing a newer server build with an older cached/published JS bundle. Custom rendermode registrations that produce renderer IDs outside the known set.
Related errors
- Invalid component type '${type}'.
- Cannot supply a component of type '{componentType}' because
- Dynamic root components have already been enabled.
- 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/b3d3e2318e291fd0.
Report an issue: GitHub.