Skip to content

fix(tooltip): guard against removed series in cached axis tooltip params (Fixes #21732) - #21737

Open
waterWang wants to merge 1 commit into
apache:masterfrom
waterWang:fix/axis-tooltip-stale-series-21732
Open

fix(tooltip): guard against removed series in cached axis tooltip params (Fixes #21732)#21737
waterWang wants to merge 1 commit into
apache:masterfrom
waterWang:fix/axis-tooltip-stale-series-21732

Conversation

@waterWang

Copy link
Copy Markdown

Fixes #21732

Problem

TooltipView._showAxisTooltip iterates axisItem.seriesDataIndices whose seriesIndex values come from the cached pointer state (_lastDataByCoordSys). When a merged setOption removes series (e.g. replaceMerge: ['series', ...]) while the tooltip is still showing, those cached indices become stale and ecModel.getSeriesByIndex(idxItem.seriesIndex) returns undefined, causing:

Uncaught TypeError: Cannot read properties of undefined (reading 'getDataParams')
    at TooltipView._showAxisTooltip

Root cause

  1. TooltipView caches the last hovered pointer state in _lastX / _lastY / _lastDataByCoordSys.
  2. Every setOption runs TooltipView.render()_keepShow(), which re-shows the tooltip with the cached dataByCoordSys after the update.
  3. The new option has fewer series than the cached indices refer to → getSeriesByIndex returns undefinedseries.getDataParams(...) throws.

Fix

Two defensive guards in _showAxisTooltip:

  1. Skip stale seriesDataIndices entries whose series no longer exists: if (!series) { return; }
  2. Move the existing !axisModel guard before the axisModel.axis access (it was previously checked after being dereferenced), so a removed axis also short-circuits instead of crashing.

Test

With tooltip: {trigger: 'axis'}, hover to show the tooltip, then setOption with fewer series in merge mode — the tooltip no longer throws and safely skips removed series.

Fixes apache#21732

_showAxisTooltip iterates `axisItem.seriesDataIndices` whose seriesIndex
values come from the cached `_lastDataByCoordSys` pointer state. When a
merged setOption removes series (e.g. `replaceMerge: ['series']`), those
indices become stale and `getSeriesByIndex` returns undefined, causing:

  Uncaught TypeError: Cannot read properties of undefined (reading getDataParams)

Also moved the `!axisModel` guard before the `axisModel.axis` access so a
removed axis handles the same way instead of crashing earlier.
@echarts-bot

echarts-bot Bot commented Aug 16, 2026

Copy link
Copy Markdown

Thanks for your contribution!
The community will review it ASAP. In the meanwhile, please checkout the coding standard and Wiki about How to make a pull request.

Please DO NOT commit the files in dist, i18n, and ssr/client/dist folders in a non-release pull request. These folders are for release use only.

To reviewers: If this PR is going to be described in the changelog in the future release, please make sure this PR has one of the following labels: PR: doc ready, PR: awaiting doc, PR: doc unchanged

This message is shown because the PR description doesn't contain the document related template.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Cached tooltip content can remain stale, and regression coverage is missing.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Hardens cached axis-tooltip refreshes after merged updates remove axes or series.

Changes:

  • Guards missing axis models before dereferencing.
  • Skips stale series references during tooltip generation.
  • Adds defensive handling, but cached tooltip content may remain stale.
File summaries
File Review summary
src/component/tooltip/TooltipView.ts Adds axis and series guards. Two moderate findings remain about stale cached content, plus one nit requesting regression coverage.
Review details

Suppressed comments (2)

src/component/tooltip/TooltipView.ts:558

  • This short-circuit avoids the null dereference, but it leaves _lastDataByCoordSys pointing at the same cached data. _updateContentNotChangedOnAxis can therefore compare the cache against itself, return true, and only move the existing tooltip instead of rebuilding it; the tooltip can continue displaying the removed axis's old content. Mark the cached content invalid when this guard fires so the tooltip is rebuilt or hidden.
                if (!axisModel || axisValue == null) {

src/component/tooltip/TooltipView.ts:583

  • Please add a regression case for the cached axis-tooltip path: keep the pointer over a chart with several series, then call merged setOption with replaceMerge: ['series', 'xAxis', 'yAxis'] so the asynchronous _keepShow callback processes stale indices. The repository has browser tooltip/setOption cases, but this change adds no coverage for the uncaught stale-series/removed-axis scenario, so this guard could regress unnoticed.
                    if (!series) {
                        return;
                    }
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.


each(axisItem.seriesDataIndices, function (idxItem) {
const series = ecModel.getSeriesByIndex(idxItem.seriesIndex);
if (!series) {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Axis tooltip throws "reading 'getDataParams'" when a merged setOption removes series

2 participants