{"record":{"id":"ea5f2c7cd61c3266","repo":"dotnet/aspnetcore","slug":"could-not-find-an-end-component-comment-for-sta","errorCode":null,"errorMessage":"Could not find an end component comment for '${start}'.","messagePattern":"Could not find an end component comment for '(.+?)'\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts","lineNumber":211,"sourceCode":"    if (node.nodeType !== Node.COMMENT_NODE) {\n      continue;\n    }\n    if (!node.textContent) {\n      continue;\n    }\n\n    const definition = blazorCommentRegularExpression.exec(node.textContent);\n    const json = definition && definition[1];\n    if (!json) {\n      continue;\n    }\n\n    validateEndComponentPayload(json, prerenderId);\n\n    return node as Comment;\n  }\n\n  throw new Error(`Could not find an end component comment for '${start}'.`);\n}\n\nlet nextUniqueDescriptorId = 0;\n\nfunction createServerComponentComment(payload: ServerComponentMarker, start: Comment, end: Comment | undefined): ServerComponentDescriptor {\n  validateServerComponentPayload(payload);\n\n  return {\n    ...payload,\n    uniqueId: nextUniqueDescriptorId++,\n    start,\n    end,\n  };\n}\n\nfunction createWebAssemblyComponentComment(payload: WebAssemblyComponentMarker, start: Comment, end: Comment | undefined): WebAssemblyComponentDescriptor {\n  validateWebAssemblyComponentPayload(payload);\n","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/294cab2f9b2e03af6b953820c7ab497c3c8b7ad9/src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts#L193-L229","documentation":"Thrown by getComponentEndComment (ComponentDescriptorDiscovery.ts:211) when a component marker carries a prerenderId (meaning the component is prerendered and bounded by a start AND end comment), but the iterator walked through all sibling nodes without finding the matching end comment. Prerendered components emit <!--Blazor:{...prerenderId...}--> ... <!--Blazor:{prerenderId:...}--> pairs; a missing end comment means the prerendered output was truncated.","triggerScenarios":"A start marker with prerenderId present but its sibling subtree contains no end marker matching blazorCommentRegularExpression; happens when response streaming is cut, HTML is truncated, or an external process removed the end comment.","commonSituations":"Response compression or buffering that truncates long streamed SSR responses; a reverse proxy with a response body size cap; partial render due to an exception during prerendering that aborts before the end marker is emitted; CSS/HTML minifier that drops the trailing comment; custom Razor partial that does not emit the closing marker.","solutions":["View the full raw HTML source to confirm both the start <!--Blazor:{...}--> and end <!--Blazor:{prerenderId:...}--> comments are present.","Increase or remove response body size limits on proxies/load balancers for Blazor pages.","Disable HTML comment stripping minifiers on Blazor routes.","Check server logs for exceptions during prerender that would abort before the end marker writes."],"exampleFix":"// before: proxy truncates streamed response\nproxy_buffer_size 4k;\n\n// after: allow full streamed SSR\nproxy_buffering off;\n# or size buffers to the largest prerendered page","handlingStrategy":"validation","validationCode":"function findPairedMarkers(root: ParentNode): { start: Comment; end: Comment }[] {\n  const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);\n  const starts = new Map<string, Comment>();\n  const pairs: {start:Comment,end:Comment}[] = [];\n  let n: Node | null;\n  while ((n = walker.nextNode())) {\n    const c = n as Comment;\n    const m = /^\\s*Blazor:[^{]*(?<descriptor>.*)$/.exec(c.textContent || '');\n    if (!m) continue;\n    const payload = JSON.parse(m.groups!.descriptor);\n    if (payload.prerenderId && !starts.has(payload.prerenderId)) starts.set(payload.prerenderId, c);\n    else if (payload.prerenderId) pairs.push({ start: starts.get(payload.prerenderId)!, end: c });\n  }\n  return pairs;\n}","typeGuard":"function hasMatchingEndMarker(startPayload: { prerenderId?: string }, candidates: Comment[]): boolean {\n  if (!startPayload.prerenderId) return true;\n  return candidates.some(c => {\n    try { return JSON.parse((/^\\s*Blazor:[^{]*(?<d>.*)$/.exec(c.textContent||'')?.groups!.d) || '{}').prerenderId === startPayload.prerenderId; }\n    catch { return false; }\n  });\n}","tryCatchPattern":null,"preventionTips":["Ensure streamed SSR responses are not truncated by proxy buffers.","Disable HTML comment minification on Blazor routes.","Confirm server logs show no prerender exceptions."],"tags":["blazor","ssr","prerendering","markers","streaming","truncation","proxy"],"analyzedSha":"294cab2f9b2e03af6b953820c7ab497c3c8b7ad9","analyzedAt":"2026-08-06T20:08:02.189Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}