Skip to content

Fix crash on disable when another extension's panel actors are already disposed#2512

Open
wormuz wants to merge 1 commit into
home-sweet-gnome:masterfrom
wormuz:fix/disposed-actors-on-disable
Open

Fix crash on disable when another extension's panel actors are already disposed#2512
wormuz wants to merge 1 commit into
home-sweet-gnome:masterfrom
wormuz:fix/disposed-actors-on-disable

Conversation

@wormuz

@wormuz wormuz commented Jun 14, 2026

Copy link
Copy Markdown

Describe the bug

Dash-to-Panel crashes during disable() when another extension that owns
actors in the shared top panel has already been disabled (and its actors
finalized) before dash-to-panel's turn.

A reliable real-world trigger: the snap firmware-updater notifier runs on a
schedule and calls gnome-extensions disable ubuntu-appindicators. Its
AppIndicatorsIconActor objects are finalized, then dash-to-panel is disabled
and PanelStyle._removeStyles() recursively walks every panel child to restore
styles — touching those dead actors:

TypeError: this._indicator is null
  _waitForFullyReady@.../ubuntu-appindicators/appIndicator.js
  _refreshPanelButton@panelStyle.js
  _restoreOriginalStyle@panelStyle.js
  _recursiveApply@panelStyle.js
  _applyStylesRecursively@panelStyle.js
  _removeStyles@panelStyle.js
  disable@panelStyle.js

Accompanied by repeated:

Object .Gjs_ubuntu-appindicators..._AppIndicatorsIconActor, has been already
disposed — impossible to access it.

Accessing a finalized GObject throws, which spams the journal and aborts the
rest of the style-restore pass (panel left half-restored / flickering).

Root cause

_recursiveApply() / _refreshPanelButton() assume every actor reachable from
the panel is still alive. We don't control the order in which extensions are
disabled, so actors owned by other extensions may already be finalized.

Fix

  • Add Utils.isValidActor() — probes whether an actor's underlying GObject is
    still alive (touching a finalized one throws).
  • Skip dead actors at the top of _recursiveApply().
  • Add a null-parent guard in _refreshPanelButton() for actors detached by
    their owning extension.

No behaviour change for live actors; only already-disposed ones are skipped.

Related to #2439 (same class of disposed-actor crashes).

Environment

  • Ubuntu 24.04, GNOME Shell 46, Wayland
  • Dash-to-Panel v73

…y disposed

When extensions are disabled in an order we don't control (e.g. the snap
firmware-updater notifier disables ubuntu-appindicators on a schedule),
its AppIndicatorsIconActor objects living in the shared panel can be
finalized before dash-to-panel's own disable() runs.

PanelStyle._removeStyles() recursively walks every panel child to restore
styles, touching those already-disposed actors:

  TypeError: this._indicator is null
    _refreshPanelButton@panelStyle.js
    _restoreOriginalStyle@panelStyle.js
    _recursiveApply@panelStyle.js
    _applyStylesRecursively@panelStyle.js
    _removeStyles@panelStyle.js

Accessing a finalized GObject throws ('has been already disposed'),
spamming the journal and breaking the rest of the restore pass.

Add Utils.isValidActor() to probe an actor's liveness and skip dead ones
at the top of _recursiveApply(), plus a null-parent guard in
_refreshPanelButton(). Related to home-sweet-gnome#2439.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant