mermaid-js/mermaid · error · Error

C4 rel "${rel.from}" -> "${rel.to}" references an unknown sh

Error message

C4 rel "${rel.from}" -> "${rel.to}" references an unknown shape

What it means

Thrown by the C4 drawRels function when getC4ShapeObj(rel.from) or getC4ShapeObj(rel.to) returns undefined. Every relationship must reference a C4 shape (Person, System, Component, Container, Boundary, etc.) that has already been declared and is in scope. A miss means the alias does not resolve to any known shape.

Source

Thrown at packages/mermaid/src/diagrams/c4/c4Renderer.ts:397

      rel.label.text = i + ': ' + rel.label.text;
    }
    let textLimitWidth = calculateTextWidth(rel.label.text, relConf as TextDimensionConfig);
    calcC4ShapeTextWH('label', rel, relTextWrap, relConf, textLimitWidth);

    if (rel.techn && rel.techn.text !== '') {
      textLimitWidth = calculateTextWidth(rel.techn.text, relConf as TextDimensionConfig);
      calcC4ShapeTextWH('techn', rel, relTextWrap, relConf, textLimitWidth);
    }

    if (rel.descr && rel.descr.text !== '') {
      textLimitWidth = calculateTextWidth(rel.descr.text, relConf as TextDimensionConfig);
      calcC4ShapeTextWH('descr', rel, relTextWrap, relConf, textLimitWidth);
    }

    const fromNode = getC4ShapeObj(rel.from);
    const endNode = getC4ShapeObj(rel.to);
    if (!fromNode || !endNode) {
      throw new Error(`C4 rel "${rel.from}" -> "${rel.to}" references an unknown shape`);
    }
    const points = getIntersectPoints(fromNode, endNode);
    if (!points.startPoint || !points.endPoint) {
      throw new Error(
        `Could not calculate intersection points for rel "${rel.from}" -> "${rel.to}"`
      );
    }
    rel.startPoint = points.startPoint;
    rel.endPoint = points.endPoint;
  }
  svgDraw.drawRels(diagram, rels, conf, diagramId);
};

async function drawInsideBoundary(
  diagram: SVG,
  parentBoundaryAlias: string,
  parentBounds: Bounds,
  currentBoundaries: C4Boundary[],

View on GitHub (pinned to d93e9c88c0)

Solutions

  1. Verify both `from` and `to` aliases are declared earlier in the C4 DSL.
  2. Check spelling and case — aliases must match exactly.
  3. If a shape is inside a boundary, ensure the relationship is evaluated in a scope where that shape is visible.

Example fix

// before
Person(personA, 'A')
Rel(personA, systemZ, 'uses')  // systemZ never declared
// after
Person(personA, 'A')
System(systemZ, 'Z')
Rel(personA, systemZ, 'uses')
Defensive patterns

Strategy: validation

Validate before calling

function assertRelTargetsExist(rel, resolveAlias) {
  if (!resolveAlias(rel.from) || !resolveAlias(rel.to)) {
    throw new Error(`Rel references unknown shape: ${rel.from} -> ${rel.to}`);
  }
}

Type guard

const relTargetsExist = (rel, resolveAlias) =>
  Boolean(resolveAlias(rel.from)) && Boolean(resolveAlias(rel.to));

Prevention

When it happens

Trigger: A C4 `Rel` directive whose `from` or `to` alias was never declared, was declared in a different (out-of-scope) boundary, or is misspelled. e.g. Rel(personA, systemZ, 'uses') where 'systemZ' is not defined.

Common situations: Typo in an alias; referencing a shape declared inside a different boundary that isn't propagated to the current scope; case mismatch (aliases are case-sensitive); renaming a shape without updating its relationships.

Related errors


AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12). Data as JSON: /api/errors/4e7402d978527798. Report an issue: GitHub.