Hooks and events issues#

A callback never runs#

Confirm that the callback is registered on the same live viewer object shown in the notebook, and that viewer.debug_connection()["channel_connected"] is True. Reproduce one event, then inspect the /_cellucid/ws WebSocket in the browser’s Network panel (filter WS); preserve its close code and reason if it closed, and any exception logged by cellucid.viewer_channel.

A command targets the wrong viewer#

Send it from the viewer object that owns the displayed frame. This is especially important when a notebook contains multiple viewers or a cell was re-run: each viewer has its own channel.

Session request rejected#

A session answers exactly one pending request and is single-use; one that arrives after the request was cancelled or stopped waiting is dropped. Start a new request instead: request = viewer.request_session(), and request.result() – in a notebook in the next cell, since the widget hears the viewer only between cells.

A session file pushed into the viewer did not load#

viewer.load_session(path) returns its request at once. Collect it – request.result(), in a notebook in a later cell – and it raises RuntimeError with the viewer’s reason when the viewer did not load the file: a session saved on another dataset, a damaged file, or a viewer that shows a dataset this notebook did not open. A missing path raises FileNotFoundError before anything is sent.

A turn raised#

with viewer.turn(label): needs a label (what the turn does, in a few words), and turns do not nest: opening one inside another raises RuntimeError naming the turn already open. Close the first, or put the actions in one turn.

viewer.history says nothing yet#

viewer.history.last_change is None until the viewer tells its first change of the history (history_changed); in a notebook that arrives between cells. Read it in a later cell, or run code on each change with @viewer.on_history_change.

An action returned without changing the viewer#

An action returns its request at once: viewer.color_by(...) does not wait for the viewer. Collect it – request.result(), in a notebook in a later cell – and it raises ActionError with the viewer’s reason when the viewer refused it. A refusal also comes back as a command_error event, printed to sys.stderr and listed by viewer.debug_connection()["recent_events"]["command_errors"]. Handle it in code with @viewer.on_command_error.

Event payload rejected#

Treat event and command schemas as exact contracts. Compare the emitted event name and payload fields with Reference (hooks, commands, schemas, endpoints).

For a complete symptom catalog, see Troubleshooting (hooks).