{"record":{"id":"bc6b0d6f1699d76a","repo":"dotnet/aspnetcore","slug":"cannot-merge-mismatching-component-descriptors","errorCode":null,"errorMessage":"Cannot merge mismatching component descriptors:\n${JSON.stringify(target)}\nand\n${JSON.stringify(source)}","messagePattern":"Cannot merge mismatching component descriptors:\n(.+?)\nand\n(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts","lineNumber":351,"sourceCode":"  } as unknown as ComponentMarker;\n}\n\nfunction doKeysMatch(a: MarkerKey | undefined, b: MarkerKey | undefined) {\n  if (!a || !b) {\n    // Unspecified keys are never considered to be matching\n    return false;\n  }\n\n  return a.locationHash === b.locationHash && a.formattedComponentKey === b.formattedComponentKey;\n}\n\nexport function canMergeDescriptors(target: ComponentDescriptor, source: ComponentDescriptor): boolean {\n  return target.type === source.type && doKeysMatch(target.key, source.key);\n}\n\nexport function mergeDescriptors(target: ComponentDescriptor, source: ComponentDescriptor) {\n  if (!canMergeDescriptors(target, source)) {\n    throw new Error(`Cannot merge mismatching component descriptors:\\n${JSON.stringify(target)}\\nand\\n${JSON.stringify(source)}`);\n  }\n\n  target.uniqueId = source.uniqueId;\n\n  if (target.type === 'webassembly' || target.type === 'auto') {\n    const sourceWebAssemblyData = source as WebAssemblyMarkerData;\n    target.parameterDefinitions = sourceWebAssemblyData.parameterDefinitions;\n    target.parameterValues = sourceWebAssemblyData.parameterValues;\n  }\n\n  if (target.type === 'server' || target.type === 'auto') {\n    const sourceServerData = source as ServerMarkerData;\n    target.sequence = sourceServerData.sequence;\n    target.descriptor = sourceServerData.descriptor;\n  }\n}\n\nexport type ComponentDescriptor = ServerComponentDescriptor | WebAssemblyComponentDescriptor | AutoComponentDescriptor;","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts#L333-L369","documentation":"Thrown by mergeDescriptors (ComponentDescriptorDiscovery.ts:351) when canMergeDescriptors returns false. Two descriptors can merge only if they share the same 'type' AND their 'key' (locationHash + formattedComponentKey) match. This guards against merging descriptors that describe different logical components (e.g. different routes or component keys) during streaming SSR reconciliation.","triggerScenarios":"Calling mergeDescriptors on two descriptors whose type differs, or whose key.locationHash / key.formattedComponentKey differ (or one/both keys are undefined). Reached during enhanced-navigation DOM syncing when an incoming streamed update targets a different component than the one already in the DOM.","commonSituations":"Navigating between pages that share DOM structure but different component keys/route parameters; @key mismatches causing Blazor to pair wrong elements; prerendered content from a different route lingering in the DOM; version mismatch in key hashing.","solutions":["Ensure consistent @key usage on components so Blazor pairs the right descriptors.","Verify the route and parameters match between the streamed update and the existing DOM.","Match framework versions so locationHash/formattedComponentKey computation agrees.","Reproduce with enhanced nav disabled to confirm the issue is in descriptor merging, then fix the @key/route source."],"exampleFix":"<!-- before: list items without stable keys -->\n@foreach (var item in Items) { <MyItem Item=\"item\" /> }\n\n<!-- after: stable keys prevent descriptor mis-pairing -->\n@foreach (var item in Items) { <MyItem Item=\"item\" @key=\"item.Id\" /> }","handlingStrategy":"validation","validationCode":"import { canMergeDescriptors } from './ComponentDescriptorDiscovery';\n\nfunction safeMerge(target, source) {\n  if (!canMergeDescriptors(target, source)) {\n    throw new Error('Refusing to merge mismatched descriptors — check @key/route parity');\n  }\n  mergeDescriptors(target, source);\n}","typeGuard":"function keysMatch(a, b): boolean {\n  return !!a && !!b && a.locationHash === b.locationHash\n    && a.formattedComponentKey === b.formattedComponentKey;\n}","tryCatchPattern":"try {\n  mergeDescriptors(target, source);\n} catch (e) {\n  if (/Cannot merge mismatching component descriptors/.test((e as Error).message)) {\n    // log and skip; reconcile via full re-render instead of merging\n  } else { throw e; }\n}","preventionTips":["Use stable @key on list items and routable components.","Keep route parameters consistent between streamed updates and DOM.","Pin framework versions so locationHash/formatting agree."],"tags":["blazor","ssr","streaming","descriptors","keys","reconciliation","enhanced-nav"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}