dash icon indicating copy to clipboard operation
dash copied to clipboard

[BUG] RangeError: Maximum call stack size exceeded in callback graph with circular dependencies

Open samlishak-artemis opened this issue 4 years ago • 8 comments

Describe your context

dash                          1.20.0
dash-bootstrap-components     0.12.2
dash-core-components          1.16.0
dash-html-components          1.1.3
dash-renderer                 1.9.1
dash-table                    4.11.3
  • if frontend related, tell us your Browser, Version and OS

    • OS: macOS Big Sur
    • Browser: Chrome
    • Version: 90.0.4430.212 (Official Build) (x86_64)

Describe the bug

When clicking the green box in the callback graph for a specific callback with circular dependencies, the callback graph crashes with the following stack trace:

RangeError: Maximum call stack size exceeded

    at RegExp.exec (<anonymous>)
    at RegExp.[Symbol.replace] (<anonymous>)
    at String.replace (<anonymous>)
    at cleanMetaChars (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:16216:14)
    at Object.populate (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:16315:14)
    at Selector.parse (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:16723:31)
    at new Selector (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:17209:15)
    at Collection.filter (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:19727:14)
    at getEdgeTypes (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:97032:21)
    at ascend (http://127.0.0.1:8080/_dash-component-suites/dash_renderer/dash_renderer.v1_9_1m1617985068.dev.js:97057:19)

The above error occurred in the <CallbackGraph> component:
    in CallbackGraph (created by UnconnectedCallbackGraphContainer)
    in UnconnectedCallbackGraphContainer (created by ConnectFunction)
    in ConnectFunction (created by DebugMenu)
    in div (created by DebugMenu)
    in div (created by DebugMenu)
    in div (created by DebugMenu)
    in DebugMenu (created by UnconnectedGlobalErrorContainer)
    in div (created by UnconnectedGlobalErrorContainer)
    in UnconnectedGlobalErrorContainer (created by withRadiumContexts(UnconnectedGlobalErrorContainer))
    in withRadiumContexts(UnconnectedGlobalErrorContainer) (created by ConnectFunction)
    in ConnectFunction (created by UnconnectedContainer)
    in UnconnectedContainer (created by ConnectFunction)
    in ConnectFunction (created by UnconnectedAppContainer)
    in UnconnectedAppContainer (created by ConnectFunction)
    in ConnectFunction (created by AppProvider)
    in Provider (created by AppProvider)
    in AppProvider

React will try to recreate this component tree from scratch using the error boundary you provided, UnconnectedCallbackGraphContainer.

~~So far I haven't reproduced this bug individually so I don't know if it's caused by the circular dependency - I will update this issue with more information if I manage to reproduce it.~~ Confirmed that it is reproducible with the simple circular callback example from the Dash docs.

Expected behavior

Should show stats for that callback when clicking the box.

Screenshots

image image

samlishak-artemis avatar May 27 '21 14:05 samlishak-artemis

This issue can be reproduced using the standard "Circular callbacks" example from the docs:

import dash
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div(
    [
        dcc.Slider(
            id="slider-circular", min=0, max=20, 
            marks={i: str(i) for i in range(21)}, 
            value=3
        ),
        dcc.Input(
            id="input-circular", type="number", min=0, max=20, value=3
        ),
    ]
)
@app.callback(
    Output("input-circular", "value"),
    Output("slider-circular", "value"),
    Input("input-circular", "value"),
    Input("slider-circular", "value"),
)
def callback(input_value, slider_value):
    ctx = dash.callback_context
    trigger_id = ctx.triggered[0]["prop_id"].split(".")[0]
    value = input_value if trigger_id == "input-circular" else slider_value
    return value, value

if __name__ == '__main__':
    app.run_server(debug=True)

image

samlishak-artemis avatar Jul 15 '21 09:07 samlishak-artemis

Did you ever figure out a solution or a workaround for this? I am running into the same issue.

kravitsjacob avatar Jul 19 '21 23:07 kravitsjacob

Unfortunately not!

samlishak-artemis avatar Jul 20 '21 07:07 samlishak-artemis

I also ran into this and posted on the plotly community https://community.plotly.com/t/callback-graph-throws-maximum-call-stack-size-exceeded-error-on-circular-callback-example/63480

nathan-chan-brt avatar Apr 28 '22 16:04 nathan-chan-brt

One possible workaround could be to use the CycleBreaker transform from dash-extensions,

https://www.dash-extensions.com/pages/transforms/cycle-breaker-transform

emilhe avatar Jul 31 '22 09:07 emilhe