{"record":{"id":"57d81eb576803e90","repo":"mermaid-js/mermaid","slug":"text-requires-set","errorCode":null,"errorMessage":"text requires set","messagePattern":"text requires set","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mermaid/src/diagrams/venn/parser/venn.jison","lineNumber":91,"sourceCode":"  | 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); }\n  ;\n\nstylesOpt\n  : styleField                  { $$ = [$styleField] }\n  | stylesOpt COMMA styleField  { $$ = [...$stylesOpt, $styleField] }\n  ;\n\nstyleField\n  : IDENTIFIER COLON styleValue { $$ = [$1, $3] }\n  ;\n\nstyleValue\n  : STRING                       { $$ = $1; }\n  | valueTokens                  { $$ = $valueTokens.join(' '); }","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/mermaid-js/mermaid/blob/d93e9c88c01a599c062ee6a3f1462e3558ac6b90/packages/mermaid/src/diagrams/venn/parser/venn.jison#L73-L109","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure a 'set' or 'union' statement precedes each indented 'text' group, since addSubsetData is what populates currentSets.","Use the inline form 'text identifierList value' (venn.jison:81-85), which carries its own explicit set list and does not depend on currentSets.","Verify the text line is indented under the intended set/union and that no clear/reset happened between them."],"exampleFix":"// before\nvenn-beta\n  text A1\n\n// after\nvenn-beta\n  set A\n    text A1","handlingStrategy":"validation","validationCode":"// Ensure every indented 'text' has a preceding set/union in scope.\nfunction validateIndentedText(src) {\n  let hasCurrentSet = false;\n  for (const raw of src.split('\\n')) {\n    if (/^\\s*(set|union)\\b/i.test(raw)) { hasCurrentSet = true; continue; }\n    if (/^\\s+text\\b/i.test(raw) && !hasCurrentSet) {\n      throw new Error('text requires a preceding set/union: ' + raw.trim());\n    }\n  }\n}","typeGuard":"function isTextRequiresSetError(e) { return e instanceof Error && /text requires set/.test(e.message); }","tryCatchPattern":"try {\n  venn.parse(src);\n} catch (e) {\n  if (e instanceof Error && /text requires set/.test(e.message)) {\n    // indented text needs a parent set/union; suggest the inline 'text <sets> <value>' form\n  } else throw e;\n}","preventionTips":["Always declare the parent 'set'/'union' before its indented 'text' children.","If you cannot guarantee ordering, use the inline form 'text identifierList value' which is order-independent.","Keep text lines indented under their set so the indent-mode lexer attaches them correctly.","Run the indented-text validator above on generated venn sources."],"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"}