{"record":{"id":"68204b352d3b4a27","repo":"mermaid-js/mermaid","slug":"union-requires-multiple-identifiers","errorCode":null,"errorMessage":"union requires multiple identifiers","messagePattern":"union requires multiple identifiers","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mermaid/src/diagrams/venn/parser/venn.jison","lineNumber":77,"sourceCode":"  ;\n\ndocument\n  : /* empty */         { $$ = [] }\n  | document line       { $1.push($2); $$ = $1 }\n  ;\n\nline\n  : NEWLINE { $$ = []; }\n  | statement { $$ = $1; }\n  ;\n\nstatement\n  : TITLE                                            { yy.setDiagramTitle($1.substr(6)); $$ = $1.substr(6); }\n  | SET identifier                                   { yy.addSubsetData([$identifier], undefined, undefined); if (yy.setIndentMode) { yy.setIndentMode(true); } }\n  | SET identifier BRACKET_LABEL                     { yy.addSubsetData([$identifier], $BRACKET_LABEL, undefined); if (yy.setIndentMode) { yy.setIndentMode(true); } }\n  | SET identifier COLON NUMERIC                     { yy.addSubsetData([$identifier], undefined, parseFloat($NUMERIC)); if (yy.setIndentMode) { yy.setIndentMode(true); } }\n  | SET identifier BRACKET_LABEL COLON NUMERIC       { yy.addSubsetData([$identifier], $BRACKET_LABEL, parseFloat($NUMERIC)); if (yy.setIndentMode) { yy.setIndentMode(true); } }\n  | 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); } }\n  | 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); } }\n  | 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); } }\n  | 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); } }\n  | TEXT identifierList IDENTIFIER                     { yy.addTextData($identifierList, $IDENTIFIER, undefined); }\n  | TEXT identifierList STRING                          { yy.addTextData($identifierList, $STRING, undefined); }\n  | TEXT identifierList NUMERIC                         { yy.addTextData($identifierList, $NUMERIC, undefined); }\n  | TEXT identifierList IDENTIFIER BRACKET_LABEL        { yy.addTextData($identifierList, $IDENTIFIER, $BRACKET_LABEL); }\n  | TEXT identifierList STRING BRACKET_LABEL            { yy.addTextData($identifierList, $STRING, $BRACKET_LABEL); }\n  | INDENT_TEXT indentedTextTail                     { $$ = $2; }\n  | STYLE identifierList stylesOpt                   { yy.addStyleData($identifierList, $stylesOpt); }\n  ;\n\nindentedTextTail\n  : IDENTIFIER               { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $IDENTIFIER, undefined); }\n  | STRING                   { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $STRING, undefined); }\n  | NUMERIC                  { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $NUMERIC, undefined); }\n  | IDENTIFIER BRACKET_LABEL { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $IDENTIFIER, $BRACKET_LABEL); }\n  | STRING BRACKET_LABEL     { var cs = yy.getCurrentSets(); if (!cs) throw new Error('text requires set'); yy.addTextData(cs, $STRING, $BRACKET_LABEL); }","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/mermaid-js/mermaid/blob/d93e9c88c01a599c062ee6a3f1462e3558ac6b90/packages/mermaid/src/diagrams/venn/parser/venn.jison#L59-L95","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nvenn-beta\n  set A\n  union A\n\n// after\nvenn-beta\n  set A\n  set B\n  union A,B","handlingStrategy":"validation","validationCode":"function validateUnionLines(src) {\n  for (const line of src.split('\\n')) {\n    const m = line.match(/^\\s*union\\s+(.+?)(?:\\s*(?:\\[|:|$))/i);\n    if (!m) continue;\n    const ids = m[1].split(',').map(s => s.trim().replace(/^\"|\"$/g, '')).filter(Boolean);\n    if (ids.length < 2) throw new Error('union requires multiple identifiers: ' + line.trim());\n  }\n}","typeGuard":"function isUnionCountError(e) { return e instanceof Error && /union requires multiple identifiers/.test(e.message); }","tryCatchPattern":"try {\n  venn.parse(src);\n} catch (e) {\n  if (e instanceof Error && /union requires multiple identifiers/.test(e.message)) {\n    // tell the user each union needs >= 2 sets\n  } else throw e;\n}","preventionTips":["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."],"tags":["venn","jison","grammar","syntax","mermaid"],"backgroundTag":null,"analyzedSha":"d93e9c88c01a599c062ee6a3f1462e3558ac6b90","analyzedAt":"2026-08-12T06:23:11.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}