{"record":{"id":"345cd9cce2fb78b4","repo":"dotnet/aspnetcore","slug":"end-of-component-comment-must-have-a-value-for-the","errorCode":null,"errorMessage":"End of component comment must have a value for the prerendered property: '${json}'","messagePattern":"End of component comment must have a value for the prerendered property: '(.+?)'","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts","lineNumber":292,"sourceCode":"    throw new Error('typeName must be defined when using a descriptor.');\n  }\n\n  // Parameter definitions and values come Base64 encoded from the server, since they contain random data and can make the\n  // comment invalid. We could unencode them in .NET Code, but that would be slower to do and we can leverage the fact that\n  // JS provides a native function that will be much faster and that we are doing this work while we are fetching\n  // blazor.boot.json\n  payload.parameterDefinitions = payload.parameterDefinitions && atob(payload.parameterDefinitions);\n  payload.parameterValues = payload.parameterValues && atob(payload.parameterValues);\n}\n\nfunction validateEndComponentPayload(json: string, prerenderId: string): void {\n  const payload = JSON.parse(json) as ComponentEndMarker;\n  if (Object.keys(payload).length !== 1) {\n    throw new Error(`Invalid end of component comment: '${json}'`);\n  }\n  const prerenderEndId = payload.prerenderId;\n  if (!prerenderEndId) {\n    throw new Error(`End of component comment must have a value for the prerendered property: '${json}'`);\n  }\n  if (prerenderEndId !== prerenderId) {\n    throw new Error(`End of component comment prerendered property must match the start comment prerender id: '${prerenderId}', '${prerenderEndId}'`);\n  }\n}\n\nclass ComponentCommentIterator {\n  private childNodes: NodeListOf<ChildNode>;\n\n  private currentIndex: number;\n\n  private length: number;\n\n  public currentElement: ChildNode | undefined;\n\n  public constructor(childNodes: NodeListOf<ChildNode>) {\n    this.childNodes = childNodes;\n    this.currentIndex = -1;","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/dotnet/aspnetcore/blob/3600ca084e9c8b5f4174fc5e747f4c52d2100806/src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts#L274-L310","documentation":"Blazor emits special HTML comments as start/end markers around prerendered components, and the end marker must be a JSON object containing exactly a 'prerenderId' field that pairs it with its start marker. This error is thrown by validateEndComponentPayload when the parsed end-marker JSON has no truthy 'prerenderId' property (e.g. it is missing, empty, null, or undefined). It indicates the SSR-rendered marker payload is malformed and Blazor cannot pair the component's prerender boundaries.","triggerScenarios":"Triggered when ComponentDescriptorDiscovery parses an end-of-component comment whose JSON body lacks a prerenderId value (fails the !prerenderEndId check at line 293). Occurs after Object.keys(payload).length === 1 already passed, so the payload is a single-key object but that key is not a populated 'prerenderId'.","commonSituations":"A custom or hand-edited host page that strips/alters Blazor comment markers; an output-filtering middleware (HTML minifiers, response compressors, CDNs) that rewrites comment payloads; a mismatched Blazor server JS version vs. the blazor.web.js/blazor.server.js bundle; partial HTML caching that drops the prerenderId.","solutions":["Disable any HTML minification/compression or response-rewriting middleware that alters comment contents and re-test.","Verify the Blazor JS bundle version (blazor.web.js) exactly matches the server framework version producing the markers.","Inspect the raw HTML response for the component end comment and confirm it contains a JSON payload like {\"prerenderId\":\"<id>\"}.","If hosting behind a CDN/reverse proxy, bypass it to confirm it is not stripping comments or rewriting payloads."],"exampleFix":"// before: end marker rendered as <!-- --> (empty) due to a minifier\n// after: preserve Blazor's markers verbatim in the response pipeline\n// e.g. disable HTML minification on the Blazor endpoint:\nservices.AddHtmlMinification(o => o.MinifyComments = false);\n// or exclude Blazor routes from the minifying middleware.","handlingStrategy":"validation","validationCode":"// Before relying on a prerendered component marker, validate its shape\nfunction isValidEndMarker(json: string): boolean {\n  try {\n    const p = JSON.parse(json);\n    return p && typeof p.prerenderId === 'string' && p.prerenderId.length > 0;\n  } catch { return false; }\n}\n// if (!isValidEndMarker(payloadJson)) { /* surface a friendlier error / disable enhancement */ }","typeGuard":"function isComponentEndMarker(v: unknown): v is { prerenderId: string } {\n  return typeof v === 'object' && v !== null\n    && typeof (v as any).prerenderId === 'string'\n    && (v as any).prerenderId.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Do not run HTML minification, compression rewriting, or CDN HTML optimization on Blazor endpoints.","Keep the Blazor JS bundle and the server runtime on the exact same framework version.","Avoid caching prerendered HTML fragments across requests.","If you transform HTML responses, write a test that asserts Blazor comment markers survive round-tripping."],"tags":["blazor","ssr","prerendering","component-markers","malformed-payload"],"backgroundTag":null,"analyzedSha":"3600ca084e9c8b5f4174fc5e747f4c52d2100806","analyzedAt":"2026-08-11T16:32:30.678Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}