Dash-extensions, ServerSideOutput error

Hi Emil, I just installed new dash 2.9.3 and the code doesn’t work. so frustrated, The error is shown below. any idea why it is not working for me? Thanks

nvalidCallbackReturnValue: The callback for [<ServersideOutput store.data>, <ServersideOutput time.data>]
returned a value having type DataFrame
which is not JSON serializable.

The value in question is either the only value returned,
or is in the top level of the returned list,

            and has string representation
            `       rnd

0 0.67604`

            In general, Dash properties can only be
            dash components, strings, dictionaries, numbers, None,
            or lists of those.

Hi @roudan,

Did the same callback work before installing the latest version of dash?

Are you sure you used DashProxy and ServersideOutputTransform

app = DashProxy(transforms=[ServersideOutputTransform()])

Could you post a MWE demonstrating the issue? :slight_smile:

I’m getting the same error with 2.9.2 - it used to work fine, I’m returning a list of dataclasses. I refactored the code into pages (https://dash.plotly.com/urls) and now ServersideOutput is trying to json serialise the dataset.

I figured out how to reproduce this, if you define the callback as

@dash.callback(ServersideOutput(component_id='data-store', component_property='data'),
              Input(component_id='dropdown', component_property='value'))
def load_data(id):
    pass

It produces the error, if you replace @dash.callback with @app.callback

@app.callback(ServersideOutput(component_id='data-store', component_property='data'),
              Input(component_id='dropdown', component_property='value'))
def load_data(id):
    pass

It works fine.

Yes, that is expected behavior. You must use imports from ‘dash-extensions’ (instead of ‘dash’) for the transforms to be applied. It has always been like that, there should be no changes with Dash 2.9 :slight_smile:

The docs for multi-page dash apps suggest we use @dash.callback instead of @app.callback to remove the circular dependency where app has to import each page (therefore each page can’t import app to create the callback). What is the dash_extensions.enrich equivalent for this?

I have a single page that needs server side callbacks. At the top of the file, I call dash.register_page() and I have several @dash.callbacks() defined. I already replaced Output, Input, State, and other dash objects with the dash_extensions.enrich versions, but am not sure how the replace the dash object for the pages system.

Like for the objects, simply replace the import of the decorator, i.e. instead of dash.callback, it would be dash_extensions.enrich.callback. Or you could import the decorator at the top,

from dash_extensions.enrich import callback

...

@callback(...)
def some_callback(...):
1 Like

Hey Emil,

I’m using the transforms with vanilla Plotly Dash pages. My BlockingCallbackTransform() works in the home page, but in another file under my /pages directory, the transform does not work.

I am import like so (in /pages/page1.py):

from dash_extensions.enrich import Input, Output, State, html, dcc, dash

...

@dash.callback(Output("output", "children"), Input("trigger", "n_intervals"), blocking=True)
def update(n_intervals):
    time.sleep(5)  # emulate slow database
    return f"Hello! (n_intervals is {n_intervals})"

This doesn’t seem to be working. How do I use right import and app object with pages? In my app.py file, app is defined to the DashProxy.

Thank you!

It looks like you imported the decorator from the wrong place (i.e. dash instead of dash-extensions). Did you try,

from dash_extensions.enrich import Input, Output, State, html, dcc, callback

...

@callback(Output("output", "children"), Input("trigger", "n_intervals"), blocking=True)
def update(n_intervals):
    time.sleep(5)  # emulate slow database
    return f"Hello! (n_intervals is {n_intervals})"

Just tried this and now I seem to be getting a non-existent input error, with id=trigger. It doesn’t seem like the id’s in the page is registering.

With just the callback decorator when blocking=True is applied, there’s a non-existent ID error. With dash.callback the transform doesn’t work. I just replaced all dash, Input, html,... imports with imports from dash_extensions.enrich. Do I need to do anything else to get it to work with pages?

Should I always use the from dash_extensions.enrich import callback callback or is it OK to use the from dash_extension.enrich import dash.callback callback?

It is recommended only to use imports from dash-extensions, i.e. not the dash.callback one. The decorator will not apply transforms. Besides replacing the imports, no further changes are required.

Hmmmm, it doesn’t seem to work with pages, even with the changed imports.

As a minimal example, here’s what I have.

Structure:
app.py
pages/
└── page1.py

app.py:

from dash_extensions.enrich import DashProxy, BlockingCallbackTransform, dcc, html, Input, Output, page_container
import time

app = DashProxy(__name__, 
                transforms=[BlockingCallbackTransform()], 
                use_pages=True
)

app.layout = html.Div([
    html.Div(id="main-output"), 
    dcc.Interval(id="main-trigger"),
    page_container
])  # default interval is 1s

@app.callback(
        Output("main-output", "children"), 
        Input("main-trigger", "n_intervals"), 
        blocking=True)
def main_update(n_intervals):
    time.sleep(5)  # emulate slow database
    return f"Hello! (n_intervals is {n_intervals})"


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

pages/page1.py:

from dash_extensions.enrich import html, dcc, register_page, callback, Output, Input
import time

register_page(__name__, path="/page1")

layout = html.Div([
    html.Div(id="page1-output"), 
    dcc.Interval(id="page1-trigger"),
])  # default interval is 1s

@callback(
        Output("page1-output", "children"), 
        Input("page1-trigger", "n_intervals"), 
        blocking=True)
def page1_update(n_intervals):
    time.sleep(5)  # emulate slow database
    return f"Hello! (n_intervals is {n_intervals})"

Running this app will yield a non-existent ID error:
A nonexistent object was used in an 'Input' of a Dash callback. The id of this object is 'page1-trigger' and the property is 'n_intervals'. The string ids in the current layout are: [main-output, main-trigger, _pages_location, _pages_content, _pages_store, _pages_dummy, 3288faf5-72b8-49c0-8ba9-2c0f2c437a6d_start_client, 3288faf5-72b8-49c0-8ba9-2c0f2c437a6d_end_server, 3288faf5-72b8-49c0-8ba9-2c0f2c437a6d_end_client, 3288faf5-72b8-49c0-8ba9-2c0f2c437a6d_start_blocked, 3288faf5-72b8-49c0-8ba9-2c0f2c437a6d_start_client_ctx, 3288faf5-72b8-49c0-8ba9-2c0f2c437a6d_end_blocked, da5d9eaa-ce93-4870-a623-40a11ef09053_start_client, da5d9eaa-ce93-4870-a623-40a11ef09053_end_server, da5d9eaa-ce93-4870-a623-40a11ef09053_end_client, da5d9eaa-ce93-4870-a623-40a11ef09053_start_blocked, da5d9eaa-ce93-4870-a623-40a11ef09053_start_client_ctx, da5d9eaa-ce93-4870-a623-40a11ef09053_end_blocked]