Skip to content

ReferenceError breaks widget initialization in non-Jupyter environments #34

Closed

Description

@MarcSkovMadsen

Summary

drawdata.ScatterWidget() throws Uncaught ReferenceError: Cannot access 'circle_brush' before initialization when rendered in frameworks that use the anywidget ESM spec directly (e.g., Panel's upcoming AnyWidget pane, ). This error breaks the widget's model.on("change:...") event handlers, preventing bidirectional sync between the frontend and Python.

Screenshot

Image

Reproduction

CANNOT RUN BEFORE RELEASE OF UPCOMING PANEL ANYWIDGET PANE. SEE holoviz/panel#8428.

Minimal reproducible example (Panel)

pip install drawdata panel
# drawdata_bug.py
import panel as pn
from drawdata import ScatterWidget

pn.extension()

widget = ScatterWidget()
pane = pn.pane.AnyWidget(widget)

# Try to sync brushsize changes
brushsize_display = pn.pane.Markdown(f"**Brush size:** {widget.brushsize}")
widget.observe(
    lambda change: setattr(brushsize_display, 'object', f"**Brush size:** {change['new']}"),
    names=['brushsize']
)

pn.Column(
    "# drawdata ScatterWidget — circle_brush bug",
    pane,
    brushsize_display,
).servable()
panel serve drawdata_bug.py

Expected behavior

The ScatterWidget renders fully. Changing brushsize from Python updates the widget's brush size in the browser, and drawing points syncs back to Python via the data traitlet.

Actual behavior

The widget partially renders (canvas and class buttons appear), but the browser console shows:

Uncaught ReferenceError: Cannot access 'circle_brush' before initialization
    at button.onclick (<esm>:9611:7)
    at <esm>:9616:14
    at Array.forEach (<anonymous>)
    at h.render (<esm>:9575:14)

Additionally:

Error: <svg> attribute height: Expected length, "auto".

Because the error occurs during the render() function, the model.on("change:brushsize", ...) and model.on("change:n_classes", ...) handlers may never be registered, which breaks bidirectional sync:

  • Widget -> Python: Drawing does not sync data traitlet reliably
  • Python -> Widget: Changing widget.brushsize from Python does not update the brush in the browser

Root Cause Analysis

The circle_brush variable appears to be referenced before its declaration in the bundled ESM. This is likely a JavaScript variable hoisting issue in the build output — circle_brush is used in an onclick handler that executes during render(), but the variable declaration appears later in the bundle.

Environment

  • drawdata version: 0.5.0
  • anywidget version: 0.9.x
  • Panel version: 1.x (development branch with AnyWidget pane)
  • Python: 3.12
  • Browser: Chromium
  • OS: Linux

Notes

  • The same widget works in JupyterLab because Jupyter's comm infrastructure handles initialization differently (the widget model is fully constructed before render() is called)
  • Other anywidgets (e.g., wigglystuff, custom inline ESM widgets) render correctly in Panel, confirming this is a drawdata-specific issue
  • The <svg> attribute height: "auto" error also suggests SVG sizing issues in the ESM bundle

Activity

  1. changed the title [-]`circle_brush` ReferenceError breaks widget initialization in non-Jupyter environments[/-] [+]ReferenceError breaks widget initialization in non-Jupyter environments[/+] on Feb 21, 2026
  2. RedZapdos123 commented on Apr 23, 2026

    @RedZapdos123
    Contributor

    Non-Panel MRE:

    from drawdata import ScatterWidget
    
    widget = ScatterWidget()
    widget

    Current behavior:

    • The widget can render partially, but initialization fails in the browser with:
      ReferenceError: Cannot access 'circle_brush' before initialization.
    • Because render aborts early, later sync handlers may not attach correctly.

    This is the same underlying bug outside Panel too: ScatterWidget uses circle_brush before it is initialized during render. In the current behavior, the widget can partially render, but the browser hits Cannot access 'circle_brush' before initialization, which can break the later sync handlers.

    The PR #36 fixes this in drawdata by initializing circle_brush before it is used and guarding the early class button click path. That removes the render time ReferenceError in AnyWidget hosts, including Panel.

    The MRE screenshot:

    Image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions