mermaid-js/mermaid · error · Error
union requires multiple identifiers
Error message
union requires multiple identifiers
What it means
Thrown by the venn.jison grammar production 'UNION identifierList' (line 77) when the reduced identifierList has length < 2. In a venn-beta diagram 'union' denotes the intersection/combination region of two or more sets, so a single identifier is semantically meaningless and the grammar rejects it at reduction time before addSubsetData runs. The same guard is duplicated across the three other union productions (lines 78-80); this variant is the bare 'union A' form with no label or size.
Source
Thrown at packages/mermaid/src/diagrams/venn/parser/venn.jison:77
;
document
: /* empty */ { $$ = [] }
| document line { $1.push($2); $$ = $1 }
;
line
: NEWLINE { $$ = []; }
| statement { $$ = $1; }
;
statement
: TITLE { yy.setDiagramTitle($1.substr(6)); $$ = $1.substr(6); }
| 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); }View on GitHub (pinned to d93e9c88c0)
Solutions
- Add at least one more identifier: 'union A,B'
- If only one set is intended, use 'set A' instead of 'union A'
- Declare every referenced set with 'set' first so the subsequent validateUnionIdentifiers check (vennDB.ts:80) also passes
Example fix
// before venn-beta set A union A // after venn-beta set A set B union A,B
Defensive patterns
Strategy: validation
Validate before calling
function validateUnionLines(src) {
for (const line of src.split('\n')) {
const m = line.match(/^\s*union\s+(.+?)(?:\s*(?:\[|:|$))/i);
if (!m) continue;
const ids = m[1].split(',').map(s => s.trim().replace(/^"|"$/g, '')).filter(Boolean);
if (ids.length < 2) throw new Error('union requires multiple identifiers: ' + line.trim());
}
} Type guard
function isUnionCountError(e) { return e instanceof Error && /union requires multiple identifiers/.test(e.message); } Try / catch
try {
venn.parse(src);
} catch (e) {
if (e instanceof Error && /union requires multiple identifiers/.test(e.message)) {
// tell the user each union needs >= 2 sets
} else throw e;
} Prevention
- Remember 'union' is for intersections of 2+ sets; a lone set uses 'set'.
- Declare every set with 'set' before referencing it in a union so the later validateUnionIdentifiers check also passes.
- Validate generated venn sources with the line scanner above before rendering.
- Quote set identifiers that contain spaces or commas.
When it happens
Trigger: A venn-beta source containing a union statement that lists only one set identifier, e.g. 'union A'. The identifierList non-terminal (venn.jison:125-128) reduces to a single element, so the inline guard 'if ($identifierList.length < 2) throw' fires.
Common situations: Forgetting the comma-separated second set; using 'union' where 'set' was intended; dropping the second id while editing; assuming union accepts a single set like set does.
Related errors
- text requires set
- Error: State name must be a single word. Found: "${yytext.tr
- Parsing failed: ${lexerErrors} ${parserErrors}
- Diagram ${type} not found.
- No diagram type detected matching given configuration for te
AI-assisted analysis of mermaid-js/mermaid@d93e9c88c0 (2026-08-12).
Data as JSON: /api/errors/68204b352d3b4a27.
Report an issue: GitHub.