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

  1. Inspect the raw server-rendered HTML (View Source, not DevTools tree) for the exact <!--Blazor:{...}--> comment and validate its JSON.
  2. Disable HTML minification/rewriting (e.g. WebOptimizer, response compression that alters comments) for Blazor pages.
  3. Ensure server (.NET) and client (blazor.web.js / blazor.webassembly.js) versions match exactly.
  4. 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

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

Related errors


AI-assisted analysis of dotnet/aspnetcore@294cab2f9b (2026-08-06). Data as JSON: /api/errors/3e3fc6f62aee7131. Report an issue: GitHub.