dotnet/aspnetcore · error

Invalid end of component comment: '${json}'

Error message

Invalid end of component comment: '${json}'

What it means

Thrown by validateEndComponentPayload (ComponentDescriptorDiscovery.ts:288) when an end marker's parsed JSON object does not have exactly one key. The end marker must contain only the 'prerenderId' key; any extra or missing keys indicate the end comment is malformed.

Source

Thrown at src/Components/Web.JS/src/Services/ComponentDescriptorDiscovery.ts:288

    throw new Error('assembly must be defined when using a descriptor.');
  }

  if (!typeName) {
    throw new Error('typeName must be defined when using a descriptor.');
  }

  // Parameter definitions and values come Base64 encoded from the server, since they contain random data and can make the
  // comment invalid. We could unencode them in .NET Code, but that would be slower to do and we can leverage the fact that
  // JS provides a native function that will be much faster and that we are doing this work while we are fetching
  // blazor.boot.json
  payload.parameterDefinitions = payload.parameterDefinitions && atob(payload.parameterDefinitions);
  payload.parameterValues = payload.parameterValues && atob(payload.parameterValues);
}

function validateEndComponentPayload(json: string, prerenderId: string): void {
  const payload = JSON.parse(json) as ComponentEndMarker;
  if (Object.keys(payload).length !== 1) {
    throw new Error(`Invalid end of component comment: '${json}'`);
  }
  const prerenderEndId = payload.prerenderId;
  if (!prerenderEndId) {
    throw new Error(`End of component comment must have a value for the prerendered property: '${json}'`);
  }
  if (prerenderEndId !== prerenderId) {
    throw new Error(`End of component comment prerendered property must match the start comment prerender id: '${prerenderId}', '${prerenderEndId}'`);
  }
}

class ComponentCommentIterator {
  private childNodes: NodeListOf<ChildNode>;

  private currentIndex: number;

  private length: number;

  public currentElement: ChildNode | undefined;

View on GitHub (pinned to 294cab2f9b)

Solutions

  1. Inspect the end comment's raw JSON and confirm it has exactly {"prerenderId":"<id>"}.
  2. Match framework versions and avoid custom end-marker generation.
  3. Remove middleware that rewrites JSON inside HTML comments.
  4. Ensure prerendering completes without exceptions that abort the end marker.
Defensive patterns

Strategy: validation

Validate before calling

function isWellFormedEndMarker(json: string): boolean {
  try {
    const p = JSON.parse(json);
    return Object.keys(p).length === 1 && 'prerenderId' in p;
  } catch { return false; }
}

Type guard

function isEndMarker(payload: any): payload is { prerenderId: string } {
  return payload && Object.keys(payload).length === 1
    && typeof payload.prerenderId === 'string' && payload.prerenderId.length > 0;
}

Prevention

When it happens

Trigger: An end comment <!--Blazor:{...}--> whose JSON parses to an object with 0 or 2+ keys (e.g. {prerenderId:'x', extra:1} or {}). Typically a hand-edited or rewritten end comment.

Common situations: HTML transformation injecting extra fields; version mismatch changing the end-marker schema; corrupted prerendered output; custom serializer for end markers.

Related errors


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