dotnet/aspnetcore · error
Found malformed component comment at ${candidateStart.textCo
Error message
Found malformed component comment at ${candidateStart.textContent} What it means
A catch-all in getComponentComment (ComponentDescriptorDiscovery.ts:160) that re-wraps any exception thrown while parsing a Blazor component marker comment (the <!--Blazor:{...}--> HTML comments Blazor emits). It fires when the JSON payload of a component marker is structurally invalid so parseCommentPayload, getComponentEndComment, or the create*ComponentComment validators all throw. The wrapped message echoes the offending textContent so you can locate the corrupt marker in the DOM.
Source
Thrown at src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts:161
// Regardless of whether this comment matches the type we're looking for, we still need to move the iterator
// on to its end position since we don't want to recurse into unrelated prerendered components, nor do we want to get confused
// by the end marker.
const candidateEnd = getComponentEndComment(componentComment, candidateStart as Comment, commentNodeIterator);
if (type !== componentComment.type) {
return undefined;
}
switch (componentComment.type) {
case 'webassembly':
return createWebAssemblyComponentComment(componentComment, candidateStart as Comment, candidateEnd);
case 'server':
return createServerComponentComment(componentComment, candidateStart as Comment, candidateEnd);
case 'auto':
return createAutoComponentComment(componentComment, candidateStart as Comment, candidateEnd);
}
} catch (error) {
throw new Error(`Found malformed component comment at ${candidateStart.textContent}`);
}
} else {
return;
}
}
}
function parseCommentPayload(json: string): ServerComponentMarker | WebAssemblyComponentMarker | AutoComponentMarker {
const payload = JSON.parse(json);
const { type } = payload;
if (type !== 'server' && type !== 'webassembly' && type !== 'auto') {
throw new Error(`Invalid component type '${type}'.`);
}
return payload;
}
function assertNotDirectlyOnDocument(marker: Node) {View on GitHub (pinned to 294cab2f9b)
Solutions
- Inspect the raw server-rendered HTML (View Source, not DevTools tree) for the exact <!--Blazor:{...}--> comment and validate its JSON.
- Disable HTML minification/rewriting (e.g. WebOptimizer, response compression that alters comments) for Blazor pages.
- Ensure server (.NET) and client (blazor.web.js / blazor.webassembly.js) versions match exactly.
- Reproduce with a minimal page and add a single component to isolate which marker is malformed.
Example fix
// before (custom middleware mangling comments) output = output.replace(/<!--.*?-->/g, ''); // after // do not strip HTML comments on Blazor pages; preserve <!--Blazor:...--> markers verbatim
Defensive patterns
Strategy: validation
Validate before calling
function looksLikeBlazorMarker(commentText: string): boolean {
const re = /^\s*Blazor:[^{]*(?<descriptor>.*)$/;
const m = re.exec(commentText);
if (!m) return true; // not a Blazor marker, leave it alone
try { JSON.parse(m.groups!.descriptor); return true; } catch { return false; }
} Type guard
function isValidBlazorMarkerPayload(json: string): boolean {
try {
const p = JSON.parse(json);
return p && ['server','webassembly','auto'].includes(p.type);
} catch { return false; }
} Try / catch
try {
discoverComponents(document, 'auto');
} catch (e) {
if (/malformed component comment/.test((e as Error).message)) {
// surface a user-friendly error; disable enhanced nav and fall back to full page load
console.error('Blazor marker corruption detected:', e);
location.reload();
} else { throw e; }
} Prevention
- Never strip or rewrite HTML comments on Blazor-served pages.
- Keep server and client framework versions in lockstep.
- Validate marker JSON in middleware tests if you must transform HTML.
When it happens
Trigger: Any of: invalid JSON in the marker; marker type not server/webassembly/auto; missing descriptor/sequence/assembly/typeName; missing or mismatched prerenderId end comment; marker placed directly under document (root component marked interactive). Each inner throw is caught and re-thrown as this message.
Common situations: A reverse proxy, CDN HTML minifier, or custom middleware strips/rewrites the Blazor marker comments; a custom Razor component serializer emits malformed descriptors; SSR output is cached or transformed; mixing incompatible Blazor server and client versions where the marker schema differs; browser extensions injecting comments that match the Blazor: regex.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid component type '${type}'.
- Could not find an end component comment for '${start}'.
- descriptor must be defined when using a descriptor.
- sequence must be defined when using a descriptor.
- assembly must be defined when using a descriptor.
AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06).
Data as JSON: /api/errors/3e3fc6f62aee7131.
Report an issue: GitHub.