mermaid-js/mermaid · error · Error

text requires set

Error message

text requires set

What it means

Thrown by the indentedTextTail production 'IDENTIFIER' (venn.jison:91) when an indented text value is reduced but yy.getCurrentSets() (vennDB.ts:92) returns undefined. currentSets is assigned only inside addSubsetData (vennDB.ts:26), which runs on 'set' and 'union' lines; an indented 'text <IDENTIFIER>' therefore needs a preceding set/union to attach to. With no current set in scope the text node would be orphaned, so the grammar rejects it. The thrown value is a plain Error.

Source

Thrown at packages/mermaid/src/diagrams/venn/parser/venn.jison:91

  | SET identifier                                   { yy.addSubsetData([$identifier], undefined, undefined); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | SET identifier BRACKET_LABEL                     { yy.addSubsetData([$identifier], $BRACKET_LABEL, undefined); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | SET identifier COLON NUMERIC                     { yy.addSubsetData([$identifier], undefined, parseFloat($NUMERIC)); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | SET identifier BRACKET_LABEL COLON NUMERIC       { yy.addSubsetData([$identifier], $BRACKET_LABEL, parseFloat($NUMERIC)); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | UNION identifierList                             { if ($identifierList.length < 2) { throw new Error('union requires multiple identifiers'); } if (yy.validateUnionIdentifiers) { yy.validateUnionIdentifiers($identifierList); } yy.addSubsetData($identifierList, undefined, undefined); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | UNION identifierList BRACKET_LABEL               { if ($identifierList.length < 2) { throw new Error('union requires multiple identifiers'); } if (yy.validateUnionIdentifiers) { yy.validateUnionIdentifiers($identifierList); } yy.addSubsetData($identifierList, $BRACKET_LABEL, undefined); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | UNION identifierList COLON NUMERIC               { if ($identifierList.length < 2) { throw new Error('union requires multiple identifiers'); } if (yy.validateUnionIdentifiers) { yy.validateUnionIdentifiers($identifierList); } yy.addSubsetData($identifierList, undefined, parseFloat($NUMERIC)); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | UNION identifierList BRACKET_LABEL COLON NUMERIC { if ($identifierList.length < 2) { throw new Error('union requires multiple identifiers'); } if (yy.validateUnionIdentifiers) { yy.validateUnionIdentifiers($identifierList); } yy.addSubsetData($identifierList, $BRACKET_LABEL, parseFloat($NUMERIC)); if (yy.setIndentMode) { yy.setIndentMode(true); } }
  | TEXT identifierList IDENTIFIER                     { yy.addTextData($identifierList, $IDENTIFIER, undefined); }
  | TEXT identifierList STRING                          { yy.addTextData($identifierList, $STRING, undefined); }
  | TEXT identifierList NUMERIC                         { yy.addTextData($identifierList, $NUMERIC, undefined); }
  | TEXT identifierList IDENTIFIER BRACKET_LABEL        { yy.addTextData($identifierList, $IDENTIFIER, $BRACKET_LABEL); }
  | TEXT identifierList STRING BRACKET_LABEL            { yy.addTextData($identifierList, $STRING, $BRACKET_LABEL); }
  | INDENT_TEXT indentedTextTail                     { $$ = $2; }
  | STYLE identifierList stylesOpt                   { yy.addStyleData($identifierList, $stylesOpt); }
  ;

indentedTextTail
  : IDENTIFIER               { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $IDENTIFIER, undefined); }
  | STRING                   { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $STRING, undefined); }
  | NUMERIC                  { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $NUMERIC, undefined); }
  | IDENTIFIER BRACKET_LABEL { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $IDENTIFIER, $BRACKET_LABEL); }
  | STRING BRACKET_LABEL     { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $STRING, $BRACKET_LABEL); }
  ;

stylesOpt
  : styleField                  { $$ = [$styleField] }
  | stylesOpt COMMA styleField  { $$ = [...$stylesOpt, $styleField] }
  ;

styleField
  : IDENTIFIER COLON styleValue { $$ = [$1, $3] }
  ;

styleValue
  : STRING                       { $$ = $1; }
  | valueTokens                  { $$ = $valueTokens.join(' '); }

View on GitHub (pinned to d93e9c88c0)

Solutions

  1. Ensure a 'set' or 'union' statement precedes each indented 'text' group, since addSubsetData is what populates currentSets.
  2. Use the inline form 'text identifierList value' (venn.jison:81-85), which carries its own explicit set list and does not depend on currentSets.
  3. Verify the text line is indented under the intended set/union and that no clear/reset happened between them.

Example fix

// before
venn-beta
  text A1

// after
venn-beta
  set A
    text A1
Defensive patterns

Strategy: validation

Validate before calling

// Ensure every indented 'text' has a preceding set/union in scope.
function validateIndentedText(src) {
  let hasCurrentSet = false;
  for (const raw of src.split('\n')) {
    if (/^\s*(set|union)\b/i.test(raw)) { hasCurrentSet = true; continue; }
    if (/^\s+text\b/i.test(raw) && !hasCurrentSet) {
      throw new Error('text requires a preceding set/union: ' + raw.trim());
    }
  }
}

Type guard

function isTextRequiresSetError(e) { return e instanceof Error && /text requires set/.test(e.message); }

Try / catch

try {
  venn.parse(src);
} catch (e) {
  if (e instanceof Error && /text requires set/.test(e.message)) {
    // indented text needs a parent set/union; suggest the inline 'text <sets> <value>' form
  } else throw e;
}

Prevention

When it happens

Trigger: A venn-beta diagram in indent mode where an indented 'text <IDENTIFIER>' line (matched by the bol/INDENT_TEXT lexer rules at venn.jison:11-17) appears before any 'set' or 'union' line, so currentSets is still undefined when indentedTextTail reduces.

Common situations: Placing a text block at the top of the diagram before any set; reordering lines so a text line ends up above its set; indent mode remaining enabled across a diagram boundary after clear(); copy-paste that drops the leading set line.

Related errors


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