apache/echarts · error

levels[i].depth is mandatory and should be natural number

Error message

levels[i].depth is mandatory and should be natural number

What it means

DEV-only guard in SankeySeries data init: each entry in option.levels must carry a depth that is a natural number (>= 0). depth maps the level config to a specific layer of the sankey; missing or negative depth makes the level unplaceable, so dev builds reject it.

Source

Thrown at src/chart/sankey/SankeySeries.ts:191

    layoutInfo: LayoutRect;

    /**
     * Init a graph data structure from data in option series
     */
    getInitialData(option: SankeySeriesOption, ecModel: GlobalModel) {
        const links = option.edges || option.links || [];
        const nodes = option.data || option.nodes || [];
        const levels = option.levels || [];
        this.levelModels = [];
        const levelModels = this.levelModels;

        for (let i = 0; i < levels.length; i++) {
            if (levels[i].depth != null && levels[i].depth >= 0) {
                levelModels[levels[i].depth] = new Model(levels[i], this, ecModel);
            }
            else {
                if (__DEV__) {
                    throw new Error('levels[i].depth is mandatory and should be natural number');
                }
            }
        }

        const graph = createGraphFromNodeEdge(nodes, links, this, true, beforeLink);
        return graph.data;

        function beforeLink(nodeData: SeriesData, edgeData: SeriesData) {
            nodeData.wrapMethod('getItemModel', function (model: Model, idx: number) {
                const seriesModel = model.parentModel as SankeySeriesModel;
                const layout = seriesModel.getData().getItemLayout(idx);
                if (layout) {
                    const nodeDepth = layout.depth;
                    const levelModel = seriesModel.levelModels[nodeDepth];
                    if (levelModel) {
                        model.parentModel = levelModel;
                    }
                }

View on GitHub (pinned to 30076aedcd)

Solutions

  1. Ensure every levels entry has depth as an integer >= 0
  2. Use consecutive depths 0..N matching your node layers
  3. Drop level entries you cannot assign a depth to

Example fix

// before
levels: [{ itemStyle: { color: '#ccc' } }]

// after
levels: [
  { depth: 0, itemStyle: { color: '#ccc' } },
  { depth: 1, itemStyle: { color: '#999' } }
]
Defensive patterns

Strategy: validation

Validate before calling

(option.levels || []).forEach((l: any, i: number) => {
  if (!(l && l.depth != null && l.depth >= 0)) {
    console.error('[sankey] levels[' + i + '].depth missing or invalid');
  }
});

Type guard

const hasValidDepth = (l: any): boolean =>
  l != null && l.depth != null && typeof l.depth === 'number' && l.depth >= 0;

Prevention

When it happens

Trigger: levels: [{ ... }, { depth: undefined }, { depth: -1 }] — any entry with missing/null/non-numeric depth, or depth < 0.

Common situations: Trimmed/serialized sankey config that dropped the depth field; copying level config from another chart; partially authored levels arrays.

Related errors


AI-assisted analysis of apache/echarts@30076aedcd (2026-08-12). Data as JSON: /api/errors/54efefcb79a7b106. Report an issue: GitHub.