dotnet/aspnetcore · error · Error
Found malformed component comment at
Error message
Found malformed component comment at ${candidateStart.textContent} What it means
Thrown during component-marker discovery when parsing a Blazor component comment (server/webassembly/auto) raises any exception inside the try block. The catch wraps the underlying error with the comment's textContent for diagnostics. This is a generic 'the prerendered component marker HTML is malformed' signal; the original parse/validation error is masked by this wrapper.
Solutions
- Inspect the raw HTML served to the browser and confirm the <!--Blazor:{...}--> comments are intact and well-formed JSON.
- Disable HTML comment stripping in any minifier, CDN, or output cache.
- Align the server (prerendering) and client Blazor package versions.
- Reproduce by viewing page source and locate the comment whose content is shown in the message, then fix its payload.
- If a custom serializer is involved, ensure it emits the exact marker schema.
Defensive patterns
Strategy: validation
Validate before calling
// Validate served HTML before Blazor reads markers.
function assertCommentsIntact(html: string) {
const open = (html.match(/<!--Blazor:/g) || []).length;
const close = (html.match(/-->/g) || []).length;
if (open === 0) throw new Error('No Blazor component comments found in prerendered HTML.');
} Prevention
- Disable HTML comment stripping in minifiers/CDNs.
- Keep server and client Blazor versions aligned.
- Crawl served HTML in CI to confirm markers are intact.
- Avoid hand-editing prerendered component comments.
When it happens
Trigger: The HTML contains a <!--Blazor:...--> comment whose JSON payload is invalid or missing required fields; a custom HTML pipeline (e.g. an aggressive minifier) rewrote or stripped part of the marker; partial HTML streaming cut a comment in half.
Common situations: Output caching/compression that mangles comment payloads; a CDN or proxy that strips HTML comments; hand-edited _Host that broke the marker; version mismatch between prerendering server and client runtime producing different marker schemas.
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
- Could not find an end component comment for
- Invalid end of component comment
- Root components cannot be marked as interactive. The
- assembly must be defined when using a descriptor.
- descriptor must be defined when using a descriptor.
AI-assisted analysis of dotnet/aspnetcore@3600ca084e (2026-08-11).
Data as JSON: /api/errors/3e3fc6f62aee7131.
Report an issue: GitHub.
Appendix: 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 3600ca084e)