mermaid-js/mermaid · error · Error
C4: no shape handler for "${node.shape}"
Error message
C4: no shape handler for "${node.shape}" What it means
Thrown by the C4 renderer's shapeHandlerFor helper when a built C4 node's `shape` is falsy or has no entry in the unified `shapes` registry. The renderer looks up `shapes[node.shape]`; a miss means the C4 diagram produced a shape type the renderer cannot draw. This is generally an internal/version-mismatch issue rather than a user DSL error, since the C4 grammar only emits known shape keys.
Source
Thrown at packages/mermaid/src/diagrams/c4/c4Renderer.ts:279
currentBounds: Bounds,
diagram: SVG,
c4ShapeArray: C4Shape[],
c4ShapeKeys: string[]
) {
const mermaidConfig = getConfig();
const look = mermaidConfig.look ?? 'classic';
const renderOptions = { config: mermaidConfig };
// Namespace the shape DOM ids with the diagram id so two diagrams on one page don't
// collide (the unified shapes use node.domId for the element id).
const diagramId = diagram.attr('id') ?? '';
// `c4ShapeKeys` are the (numeric string) indices of `c4ShapeArray`.
const c4Shapes = c4ShapeKeys.map((key) => c4ShapeArray[Number(key)]);
const shapeHandlerFor = (node: ReturnType<typeof buildC4Node>) => {
const handler = node.shape ? shapes[node.shape] : undefined;
if (!handler) {
throw new Error(`C4: no shape handler for "${node.shape}"`);
}
return handler;
};
// Pass 1 (measure): render each shape, read its self-sized dimensions onto the legacy
// c4Shape, then discard the rendering. The shape is drawn again in pass 2 directly at its
// final position, so its label (and any composited sub-element) lays out under the final
// transform - drawing at the origin and translating afterwards leaves composited layers
// (e.g. anything with opacity) painting at the stale origin.
await Promise.all(
c4Shapes.map(async (c4Shape) => {
const node = buildC4Node(c4Shape, conf, conf.c4ShapePadding, look, conf.width);
node.domId = `${diagramId}-${node.id}`;
const measured = await shapeHandlerFor(node)(diagram, node, renderOptions);
c4Shape.width = node.width ?? conf.width;
c4Shape.height = node.height ?? conf.height;
c4Shape.margin = conf.c4ShapeMargin;
measured.remove();View on GitHub (pinned to d93e9c88c0)
Solutions
- Upgrade mermaid to a consistent version where c4Renderer and the shapes registry agree.
- Remove any custom/experimental C4 shape types from the diagram and use the built-in types.
- If it reproduces on the latest version with a standard C4 diagram, report it as a bug — the message is intended for exactly that case.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await mermaid.render(id, c4DiagramText);
} catch (err) {
if (err instanceof Error && err.message.startsWith('C4: no shape handler')) {
// Unsupported C4 shape for this mermaid version — simplify the diagram or upgrade.
}
throw err;
} Prevention
- Use only the built-in C4 element types (Person, System, Container, Component, Boundary, etc.).
- Keep mermaid at a consistent version across the c4 DB and the shapes registry.
When it happens
Trigger: A C4 diagram where buildC4Node returns a shape string that is not a key in the shapes registry — e.g. due to a custom or experimental shape, or a shape key renamed/removed in a version transition where the c4 DB and the shapes registry disagree.
Common situations: Mermaid version mismatch where c4Renderer expects a shape the installed shapes module doesn't register; third-party extensions adding C4 types without a render handler; partial upgrades.
Related errors
- C4 shape "${fromNode.alias}" has no intersect function. Plea
- C4 rel "${rel.from}" -> "${rel.to}" references an unknown sh
- Could not calculate intersection points for rel "${rel.from}
- Layout data is required
AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12).
Data as JSON: /api/errors/f7152a0f9a4d82db.
Report an issue: GitHub.