apache/echarts · error · Error
Circular dependency may exists:
Error message
Circular dependency may exists:
What it means
Thrown by `enableTopologicalTravel`'s `topologicalTravel` in component.ts:157. ECharts schedules component models in dependency order using Kahn's algorithm (activity-on-vertices) over the `dependencies` arrays declared on each Model (e.g. `static dependencies = ['grid', 'polar', ...]`). After draining the zero-entry queue, any main type still left in `targetNameSet` was never processed, which means it sits inside a dependency cycle. The throw is NOT guarded by `__DEV__`; only the human-readable message is — in a production build the thrown Error has an empty string as its message, so it surfaces as an Error with no text.
Source
Thrown at src/util/component.ts:157
const currComponentType = noEntryList.pop();
const currVertex = graph[currComponentType];
const isInTargetNameSet = !!targetNameSet[currComponentType];
if (isInTargetNameSet) {
callback.call(context, currComponentType, currVertex.originalDeps.slice());
delete targetNameSet[currComponentType];
}
zrUtil.each(
currVertex.successor,
isInTargetNameSet ? removeEdgeAndAdd : removeEdge
);
}
zrUtil.each(targetNameSet, function () {
let errMsg = '';
if (__DEV__) {
errMsg = makePrintable('Circular dependency may exists: ', targetNameSet, targetNameList, fullNameList);
}
throw new Error(errMsg);
});
function removeEdge(succComponentType: ComponentMainType): void {
graph[succComponentType].entryCount--;
if (graph[succComponentType].entryCount === 0) {
noEntryList.push(succComponentType);
}
}
// Consider this case: legend depends on series, and we call
// chart.setOption({series: [...]}), where only series is in option.
// If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will
// not be called, but only sereis.mergeOption is called. Thus legend
// have no chance to update its local record about series (like which
// name of series is available in legend).
function removeEdgeAndAdd(succComponentType: ComponentMainType): void {
targetNameSet[succComponentType] = true;
removeEdge(succComponentType);View on GitHub (pinned to 30076aedcd)
Solutions
- Inspect the `static dependencies` arrays of any custom or third-party component models and remove the edge that closes the cycle.
- Update, fix, or uninstall the offending extension whose dependency metadata is cyclic.
- If no custom components are involved, capture the full option + ECharts version and report it as an ECharts bug.
- Bisect ECharts versions to identify where the cyclic dependency was introduced, then pin to the last good version while it is fixed upstream.
Defensive patterns
Strategy: try-catch
Try / catch
// topologicalTravel runs inside setOption; wrap it so a cyclic dependency
// in a third-party component degrades gracefully instead of crashing render.
try {
chart.setOption(option);
} catch (e) {
// In production builds the message is an empty string for this error.
if (e instanceof Error && /Circular dependency/i.test(e.message) || (e instanceof Error && e.message === '')) {
console.error('Component dependency cycle detected; option not applied.', option);
// fall back to a known-good baseline option
chart.setOption(baselineOption);
} else {
throw e;
}
} Prevention
- When authoring a custom component model, list `dependencies` as only the components it truly reads from, and never let two models mutually depend on each other.
- Keep a dependency diagram for custom components; a cycle is usually visible as a back-edge in that graph.
- Test new/updated third-party ECharts extensions against your full option set in a dev build where the human-readable message is present.
When it happens
Trigger: A component main type's declared `dependencies` form a cycle (A depends on B and B depends on A, directly or transitively), reached during `GlobalModel` option merge / component scheduling (`topologicalTravel` at Global.ts:357 / :892). Built-in components are acyclic by design, so this requires a custom component model with cyclic `dependencies`, a buggy third-party extension, or an internal ECharts regression in dependency metadata.
Common situations: Authoring a custom component model whose `static dependencies` list loops back on itself or on another component that depends on it; installing a third-party ECharts plugin with incorrect dependency declarations; an ECharts version regression that introduced a cyclic dependency between built-ins; monkey-patching a built-in `dependencies` array.
AI-assisted analysis of apache/echarts@30076aedcd (2026-08-12).
Data as JSON: /api/errors/a60e0b9a7295ebcd.
Report an issue: GitHub.