{"record":{"id":"151fc6be7e7703d0","repo":"mermaid-js/mermaid","slug":"no-nodes-available-to-create-tree","errorCode":null,"errorMessage":"No nodes available to create tree","messagePattern":"No nodes available to create tree","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/mermaid-layout-tidy-tree/src/layout.ts","lineNumber":108,"sourceCode":"  const children = new Map<string, string[]>();\n  const parents = new Map<string, string>();\n\n  edges.forEach((edge) => {\n    const parentId = edge.start;\n    const childId = edge.end;\n\n    if (parentId && childId) {\n      if (!children.has(parentId)) {\n        children.set(parentId, []);\n      }\n      children.get(parentId)!.push(childId);\n      parents.set(childId, parentId);\n    }\n  });\n\n  const rootNodeData = nodes.find((node) => !parents.has(node.id));\n  if (!rootNodeData && nodes.length === 0) {\n    throw new Error('No nodes available to create tree');\n  }\n\n  const actualRoot = rootNodeData ?? nodes[0];\n\n  const rootNode: TidyTreeNode = {\n    id: actualRoot.id,\n    width: actualRoot.width ?? 100,\n    height: actualRoot.height ?? 50,\n    _originalNode: actualRoot,\n  };\n\n  const rootChildren = children.get(actualRoot.id) ?? [];\n  const leftChildren: string[] = [];\n  const rightChildren: string[] = [];\n\n  rootChildren.forEach((childId, index) => {\n    if (index % 2 === 0) {\n      leftChildren.push(childId);","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/mermaid-js/mermaid/blob/d93e9c88c01a599c062ee6a3f1462e3558ac6b90/packages/mermaid-layout-tidy-tree/src/layout.ts#L90-L126","documentation":"Thrown by convertToDualTreeFormat when it cannot find a root node AND nodes.length === 0. In practice this is a defensive duplicate of the empty-nodes guard at line 28: executeTidyTreeLayout already rejects empty nodes before calling convertToDualTreeFormat, so reaching this throw requires calling convertToDualTreeFormat directly (it is a private, non-exported helper) with an empty array.","triggerScenarios":"Only reachable if convertToDualTreeFormat is invoked with a zero-length nodes array outside the normal executeTidyTreeLayout entry path. Through the public API, error [0] fires first and this branch is never reached.","commonSituations":"Almost never seen by external callers; surfaces only during internal refactors or tests that call convertToDualTreeFormat directly with stubbed data.","solutions":["Do not call convertToDualTreeFormat directly; use executeTidyTreeLayout.","If testing the helper internally, supply at least one node.","Treat a real occurrence as a sign that the earlier guard in executeTidyTreeLayout was bypassed."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure convertToDualTreeFormat is never reached with empty nodes:\nif (!data.nodes || data.nodes.length === 0) {\n  throw new Error('Skipping layout: no nodes');\n}\nconst result = await executeTidyTreeLayout(data);","typeGuard":"function hasAtLeastOneNode(data: unknown): data is { nodes: { id: string }[] } {\n  return Array.isArray((data as any).nodes) && (data as any).nodes.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Never call the private convertToDualTreeFormat helper directly.","Keep the public executeTidyTreeLayout as the sole entry point so its guard always runs first."],"tags":["layout","tidy-tree","defensive","nodes"],"backgroundTag":null,"analyzedSha":"d93e9c88c01a599c062ee6a3f1462e3558ac6b90","analyzedAt":"2026-08-12T06:23:11.304Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}