[Bug]: TooltipFeature.refreshTooltip() throws "Cannot read properties of undefined (reading 'get')" when a tooltip-bearing component is created during grid teardown
Link to reproducible scenario
Intermittent teardown race — a deterministic live sample isn't feasible for a timing race. Please see the de-minified stack trace and root-cause analysis in "Describe the bug" below; the sandbox reproduces it with CPU throttling on and repeated clicks.
Describe the bug
Steps to reproduce
- Render a grid that has editable cells and at least one column with a tooltip (tooltipField, tooltipValueGetter, or a default cell tooltip).
- (To widen the async window) enable CPU throttling in devtools, e.g. 6x.
- Start creating a tooltip-bearing component — begin editing a cell, or scroll so a new tooltip-bearing cell renders.
- In the SAME tick/frame, destroy the grid: call api.destroy(), unmount the grid, or navigate away.
- Repeat the start-edit-then-destroy sequence several times.
Actual behaviour An uncaught "TypeError: Cannot read properties of undefined (reading 'get')" is thrown from TooltipFeature.refreshTooltip, after the grid has already been destroyed. Nothing visibly breaks (the grid is already gone), but it is logged as an unhandled exception and shows up in production error monitoring.
De-minified stack: at TooltipFeature.refreshTooltip // this.beans.gos.get("enableBrowserTooltips") at TooltipFeature.postConstruct // this.refreshTooltip() at Context.initBeans at Context.createBean at .createBean ...
Expected behaviour A feature/component created while the grid context is being destroyed should be a no-op, not throw. refreshTooltip() should not assume this.beans is defined.
More information Root cause — in TooltipFeature (extends AgBeanStub):
postConstruct() {
this.refreshTooltip();
}
refreshTooltip(clearWithEmptyString) {
this.browserTooltips = this.beans.gos.get("enableBrowserTooltips"); // this.beans is undefined -> throws
...
}When the owning component (a cell or cell-editor that has a tooltip) is instantiated as part of a deferred task that runs AFTER the grid/context has started to be destroyed, the beans threaded into the TooltipFeature constructor is undefined. postConstruct -> refreshTooltip() then dereferences this.beans.gos and throws. There is no guard for the feature being created against a torn-down context.
Suggested fix — guard the destroyed-context case, e.g.:
refreshTooltip(clearWithEmptyString) {
if (!this.beans) return; // or use this.isAlive() / optional chaining
this.browserTooltips = this.beans.gos.get("enableBrowserTooltips");
...
}Not specific to any grid configuration — any grid with tooltip-bearing components that can be created during/after teardown can hit it. It is a timing/teardown race, so it is intermittent; CPU throttling makes it observable. Observed via ag-grid-react, but the failing code is in AG Grid core.
Version
35.3.1 (also reproduces on the latest v36)
Does the issue occur for a specific framework only?
All languages
Is the issue only observable on a specific browser?
All browsers
Source: ag-grid/ag-grid