You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hovering over an ECharts-backed chart (heatmap, bar, pie, timeseries, …) on a dashboard with auto-refresh enabled intermittently throws one of:
TypeError: Cannot read properties of undefined (reading 'getItemModel')
TypeError: Cannot read properties of undefined (reading 'getRawIndex')
The error fires from inside ECharts' TooltipView, triggered by a zrender mousemove hit-test landing on a stale series element during an auto-refresh tick.
Stack trace (captured on a clean master reproduction):
TypeError: Cannot read properties of undefined (reading 'getItemModel')
at TooltipView._showSeriesItemTooltip (echarts/lib/component/tooltip/TooltipView.js:477)
at TooltipView._tryShow (echarts/lib/component/tooltip/TooltipView.js:358)
at TooltipView.eval (echarts/lib/component/tooltip/TooltipView.js:159) ← _initGlobalListener closure
at doEnter (echarts/lib/component/axisPointer/globalListener.js:117)
at Handler.dispatchToElement (zrender/lib/Handler.js:166)
The exact failing line inside ECharts TooltipView._showSeriesItemTooltip:
data is undefined because dataModel.getData(dataType) is being called with a dataType that no longer exists on the freshly-merged series model, while the old rendered zrender shape (and its ecData.dataType) is still hit-testable.
Steps to reproduce
Open any dashboard with ECharts-backed charts. The bundled FCC New Coder Survey 2018 dashboard reproduces reliably — tab 🚀 Aspiring Developers, the Preferred Employment Style vs Degree heatmap plus the other echarts viz on that tab.
Dashboard "..." menu → Set auto-refresh → 10 seconds → Save for this session.
Hover the cursor continuously over chart data points while auto-refresh ticks fire. A single error surfaces within 30–90 seconds of continuous hover during normal use; under a programmatic hover stress test (~90k synthetic mousemoves over 90 s crossing ~9 refresh ticks) the error reliably reproduces at least once per run.
The error is intermittent because it is a race: the hit-test has to land on a stale zrender element during the ~milliseconds between setOption({ replaceMerge: ['series'] }) swapping the series models and zrender re-rendering the shapes.
Root cause analysis
The auto-refresh setOption path in superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx uses:
This strategy was introduced in 8818fcf99e ("fix: charts flickering") and shipped with #37459 ("feat: auto refresh dashboard"). The goal was to preserve legend selection, zoom, and tooltip state across ticks on real-time dashboards and eliminate a flicker — so notMerge: false / replaceMerge: ['series'] / lazyUpdate: true are all deliberate and load-bearing.
The race is between two things ECharts does on different timelines when this combination is passed:
replaceMerge: ['series'] synchronously swaps the series models on the ecModel.
lazyUpdate: true defers the zrender render of the new shapes to the next requestAnimationFrame.
In the window between (1) and (2), the old rendered shapes are still mounted in the zrender scene and still hit-testable, but their backing SeriesModel in the new ecModel may have a different (or missing) List/dataType. A mousemove that lands inside one of those stale shapes walks the tooltip view's hit-test path (_tryShow → findEventDispatcher → _showSeriesItemTooltip), then dereferences undefined.
The existing if (!notMerge) dispatchAction({ type: 'hideTip' }) guard attempts to handle a related concern (stale visible tooltip content across a merge) but does not protect against the stale hit-test path:
It runs inside the setOption React effect, i.e. after the React re-render has already been committed.
hideTip clears _lastX/_lastY on TooltipView but does not clear zrender's hit-test cache or prevent a fresh mousemove from immediately re-entering _tryShow during the lazyUpdate window.
Proposed fix (to be validated)
Not blocking this issue on a specific fix, but a few avenues that look promising:
Refresh-time pre-teardown. Dispatch hideTip plus an axis-pointer reset on every echarts chart synchronously the moment isRefreshing flips to true in Redux — i.e. before the new data arrives and before the setOption effect fires. That eliminates the race window entirely since the zrender pointer state is cleared before the stale shapes can be hit-tested.
Hit-test guard in Superset's tooltip formatter layer. Wrap getData/getItemModel calls in the plugin-chart-echarts formatter so a mid-refresh stale dispatch becomes a no-op instead of a crash. Defensive, doesn't fix the underlying race, but cheap.
Drop lazyUpdate: true during replaceMerge ticks — would likely reintroduce the flicker that feat: auto refresh dashboard #37459 fixed, so probably off the table.
Upstream fix in ECharts: guard TooltipView._showSeriesItemTooltip against data === undefined. Worth filing upstream regardless.
Option 1 looks like the cleanest fix and would live in the auto-refresh hook rather than Echart.tsx.
Screenshots/recordings
N/A — JavaScript console error only. Happy to attach a screen recording of the reproduction if helpful.
Environment
Superset version
master / latest-dev
Python version
3.11
Node version
18 or greater
Browser
Chrome
Additional context
No Python stacktrace — frontend-only crash.
Reproduces with the default sample dashboard (FCC New Coder Survey 2018) — no custom data or feature flags required.
Bug description
Hovering over an ECharts-backed chart (heatmap, bar, pie, timeseries, …) on a dashboard with auto-refresh enabled intermittently throws one of:
The error fires from inside ECharts'
TooltipView, triggered by a zrender mousemove hit-test landing on a stale series element during an auto-refresh tick.Stack trace (captured on a clean
masterreproduction):The exact failing line inside ECharts
TooltipView._showSeriesItemTooltip:dataisundefinedbecausedataModel.getData(dataType)is being called with adataTypethat no longer exists on the freshly-merged series model, while the old rendered zrender shape (and itsecData.dataType) is still hit-testable.Steps to reproduce
The error is intermittent because it is a race: the hit-test has to land on a stale zrender element during the ~milliseconds between
setOption({ replaceMerge: ['series'] })swapping the series models and zrender re-rendering the shapes.Root cause analysis
The auto-refresh
setOptionpath insuperset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsxuses:This strategy was introduced in
8818fcf99e("fix: charts flickering") and shipped with #37459 ("feat: auto refresh dashboard"). The goal was to preserve legend selection, zoom, and tooltip state across ticks on real-time dashboards and eliminate a flicker — sonotMerge: false/replaceMerge: ['series']/lazyUpdate: trueare all deliberate and load-bearing.The race is between two things ECharts does on different timelines when this combination is passed:
replaceMerge: ['series']synchronously swaps the series models on theecModel.lazyUpdate: truedefers the zrender render of the new shapes to the nextrequestAnimationFrame.In the window between (1) and (2), the old rendered shapes are still mounted in the zrender scene and still hit-testable, but their backing
SeriesModelin the newecModelmay have a different (or missing)List/dataType. A mousemove that lands inside one of those stale shapes walks the tooltip view's hit-test path (_tryShow→findEventDispatcher→_showSeriesItemTooltip), then dereferencesundefined.The existing
if (!notMerge) dispatchAction({ type: 'hideTip' })guard attempts to handle a related concern (stale visible tooltip content across a merge) but does not protect against the stale hit-test path:setOptionReact effect, i.e. after the React re-render has already been committed.hideTipclears_lastX/_lastYonTooltipViewbut does not clear zrender's hit-test cache or prevent a fresh mousemove from immediately re-entering_tryShowduring thelazyUpdatewindow.Proposed fix (to be validated)
Not blocking this issue on a specific fix, but a few avenues that look promising:
hideTipplus an axis-pointer reset on every echarts chart synchronously the momentisRefreshingflips totruein Redux — i.e. before the new data arrives and before thesetOptioneffect fires. That eliminates the race window entirely since the zrender pointer state is cleared before the stale shapes can be hit-tested.getData/getItemModelcalls in the plugin-chart-echarts formatter so a mid-refresh stale dispatch becomes a no-op instead of a crash. Defensive, doesn't fix the underlying race, but cheap.lazyUpdate: trueduringreplaceMergeticks — would likely reintroduce the flicker that feat: auto refresh dashboard #37459 fixed, so probably off the table.TooltipView._showSeriesItemTooltipagainstdata === undefined. Worth filing upstream regardless.Option 1 looks like the cleanest fix and would live in the auto-refresh hook rather than
Echart.tsx.Screenshots/recordings
N/A — JavaScript console error only. Happy to attach a screen recording of the reproduction if helpful.
Environment
Additional context
Checklist