{"record":{"id":"7948898d8b938f0a","repo":"mermaid-js/mermaid","slug":"axes-must-be-populated-before-curves-for-reference","errorCode":null,"errorMessage":"Axes must be populated before curves for reference entries","messagePattern":"Axes must be populated before curves for reference entries","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/mermaid/src/diagrams/radar/db.ts","lineNumber":82,"sourceCode":"\nconst setCurves = (curves: Curve[]) => {\n  data.curves = curves.map((curve) => {\n    return {\n      name: curve.name,\n      label: curve.label ?? curve.name,\n      entries: computeCurveEntries(curve.entries),\n    };\n  });\n};\n\nconst computeCurveEntries = (entries: Entry[]): number[] => {\n  // If entries have axis reference, we must order them according to the axes\n  if (entries[0].axis == undefined) {\n    return entries.map((entry) => entry.value);\n  }\n  const axes = getAxes();\n  if (axes.length === 0) {\n    throw new Error('Axes must be populated before curves for reference entries');\n  }\n  return axes.map((axis) => {\n    const entry = entries.find((entry) => entry.axis?.$refText === axis.name);\n    if (entry === undefined) {\n      throw new Error('Missing entry for axis ' + axis.label);\n    }\n    return entry.value;\n  });\n};\n\nconst setOptions = (options: Option[]) => {\n  // Create a map from option names to option objects for quick lookup\n  const optionMap = options.reduce(\n    (acc, option) => {\n      acc[option.name] = option;\n      return acc;\n    },\n    {} as Record<string, Option>","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/mermaid-js/mermaid/blob/d93e9c88c01a599c062ee6a3f1462e3558ac6b90/packages/mermaid/src/diagrams/radar/db.ts#L64-L100","documentation":"Thrown by the radar diagram's computeCurveEntries() when a curve's entries reference axes by name (entry.axis is set) but the shared axes array is still empty. The radar DB needs axes registered first because reference-style entries must be reordered to match the axis order. Without axes there is no canonical ordering to map entries against, so the build aborts rather than emit silently-wrong data.","triggerScenarios":"db.setCurves(curves) is invoked before db.setAxes(axes) AND at least one curve's first entry has an `axis` cross-reference ($refText). This normally cannot happen through the parser (it walks axes then curves) but can occur when calling the db API directly, with a hand-built AST, or after a parser/clear() ordering bug that resets data between the two calls.","commonSituations":"Embedding mermaid and driving the radar db programmatically out of order; partial diagram text where an `axis` block is missing or commented out but curves still use `axis <name>` references; a regression that swaps the populateDb visit order; tests that call setCurves in isolation.","solutions":["Ensure the diagram text declares the `axis` block before the `curve` blocks (reference-mode entries require it).","If calling the db directly, call db.setAxes(...) before db.setCurves(...).","Switch curves to positional entries (drop the `axis <name>` reference) so ordering is taken from the entry list itself.","Re-run db.clear() only once at the start and verify no second clear() runs between setAxes and setCurves."],"exampleFix":"// before (broken order)\ndb.clear();\ndb.setCurves(curvesWithAxisRefs); // axes empty -> throws\ndb.setAxes(axes);\n\n// after\ndb.clear();\ndb.setAxes(axes);\ndb.setCurves(curvesWithAxisRefs);","handlingStrategy":"validation","validationCode":"// Before setCurves, ensure axes exist when entries use axis references\nconst usesRefs = curves.some(c => c.entries.length > 0 && c.entries[0].axis != null);\nif (usesRefs && db.getAxes().length === 0) {\n  throw new Error('Declare/parse axes before curves that reference them');\n}\ndb.setCurves(curves);","typeGuard":"const isAxisRefEntry = (e): e is Entry & { axis: { $refText: string } } =>\n  e != null && typeof e === 'object' && e.axis != null && typeof e.axis.$refText === 'string';","tryCatchPattern":"try {\n  db.setCurves(curves);\n} catch (e) {\n  if (e instanceof Error && /Axes must be populated/.test(e.message)) {\n    // ensure axes are set first, then retry once\n    db.setAxes(axes);\n    db.setCurves(curves);\n  } else { throw e; }\n}","preventionTips":["Always set/parse axes before curves in radar diagrams.","When driving the db directly, wrap setAxes+setCurves in a single helper that enforces order.","Use positional entries (no axis ref) if you cannot guarantee axis availability."],"tags":["radar","ordering","diagram-db","api-misuse"],"backgroundTag":null,"analyzedSha":"d93e9c88c01a599c062ee6a3f1462e3558ac6b90","analyzedAt":"2026-08-12T06:23:11.304Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}