Expected the output type to be a list or tuple but got: None

Hello everyone, I wanted to add a dropdown menu that callback to my table, I mean if I was to select test 1 dash should show me table1, and if I select test 2 dash should show me table2. It kind of work but it pops out this error

dash.exceptions.InvalidCallbackReturnValue: The callback …table.data…table.columns…table.page_size… is a multi-output.
Expected the output type to be a list or tuple but got:
None.

This is my code:

import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from engine import session
from dash.dependencies import Input, Output
import pandas as pd
from model import table1,table2
dft1 = pd.read_sql(session.query(table1).statement,session.bind)
dft2 = pd.read_sql(session.query(table2).statement,session.bind)

app = dash.Dash()

table_names = ['test1','test2']
fig_dropdown = html.Div([
    dcc.Dropdown(
        id='fig_dropdown',
        options=[{'label': x, 'value': x} for x in table_names],
        value=None

    )])
fig_plot = html.Div(dash_table.DataTable(id='table'))
app.layout = html.Div([fig_dropdown, fig_plot])

@app.callback(
        [Output('table', 'data'),
         Output('table', 'columns'),
         Output('table', 'page_size')],
         [Input('fig_dropdown', 'value')])

def name_to_table(table_names):

    if table_names == 'test1':
        [data, columns, page_size] = df1.to_dict('records'), [{'name': str(i), 'id': str(i),
                                                                 'deletable': False, 
                                                                 'renamable': True 
                                                                 } for i in df1.columns], 20,

        return [data, columns, page_size]
    elif table_names == 'test2':
        [data, columns, page_size] = df2.to_dict('records'), [{'name': str(i), 'id': str(i),
                                                                 'deletable': False,  
                                                                 'renamable': True  
                                                                 } for i in df2.columns], 20,
        return [data, columns, page_size]

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

Not too sure where it went wrong, any help would be greatly appreciated! :blush:

Your callback has the following structure

def name_to_table(table_names):
    if table_names == "test1":
        return ...
    elif table_names == "test2":
        return ...

which means that if tables_names is neither "test1" nor "test2" then no return value is specified. In this case, Python returns None, which Dash then tries to interpret as a tuple since you have a multi-output callback.

You should add a default return value at the end, or you could return dash.no_update

def name_to_table(table_names):
    if table_names == "test1":
        return ...
    elif table_names == "test2":
        return ...
    return dash.no_update, dash.no_update, dash.no_update

or you could raise PreventUpdate

from dash.exceptions import PreventUpdate

def name_to_table(table_names):
    if table_names == "test1":
        return ...
    elif table_names == "test2":
        return ...
    raise PreventUpdate
2 Likes

Hello, I use PreventUpdate and it does work!
Thank you!!

1 Like