KeyError: 'outputs_list' when using a Callback function with Dash

I’m building an app that uses Dash and Plotly to show data in graphs. With Dash, I’ve been able to get the page layout to render, but when I add @app.callback I get output_spec = kwargs.pop("outputs_list") KeyError: 'outputs_list' . There’s not a lot of answers regarding this error from Dash so It has been hard to get to the bottom of what’s causing it.

@app.callback(
        Output("conversion_rate_text", "children"),
        Output("ttr_text", "children"),
        Output("cpa_text", "children"),
        Output("cpt_text", "children"),
        Output("installs_text", "children"),
        Input('org-picker-dropdown', 'value'),
        Input('my-date-picker-range', 'start_date'),
        Input('my-date-picker-range', 'end_date')
)
def generate_report(client, appId):

    print("START")
    start_date = "2020-11-01"
    end_date = "2020-12-20"
    firebaseBucket = storage.bucket()
    print(firebaseBucket)
    url = "https://api.searchads.apple.com/api/v2/acls"
    keyBlobText = 'users/{client}/asa_accounts/{appId}/api_certificates/account.key'.format(client = client, appId = appId)
    pemBlobText = 'users/{client}/asa_accounts/{appId}/api_certificates/account.pem'.format(client = client, appId = appId)
    if firebaseBucket.blob(keyBlobText):
        print("GETTING KEY AND PEM")
        key = firebaseBucket.blob(keyBlobText)
        pem = firebaseBucket.blob(pemBlobText)
        key.download_to_filename("client.key")
        pem.download_to_filename("client.pem")
    asa_response = requests.get(url, cert=(asa_pem, asa_key))
    orgId = asa_response.json()['data'][0]['orgId']
    blobs = firebaseBucket.list_blobs()
    for blob in blobs:
        print(blob.name)
    allCampaigns = get_campaigns(client, appId, orgId, start_date, end_date)

    conversion_rate = format_rate(allCampaigns[0]['conversionRate']) + '%'
    ttr = format_rate(allCampaigns[0]['ttr']) + '%'
    cpa = format_num(allCampaigns[0]['avgCPA']['amount']) + ' ' + allCampaigns[0]['avgCPA']['currency']
    cpt = format_num(allCampaigns[0]['avgCPT']['amount']) + ' ' + allCampaigns[0]['avgCPT']['currency']
    installs = format_num(allCampaigns[0]['installs'])
    if allCampaigns:
        new_re_downloads_chart = {
            'data': [{
                    'y': ['New Downloads ', 'Re-downloads '], 
                    'x': [grand_totals['newDownloads'], grand_totals['redownloads']], 
                    'orientation':'h',
                    'type': 'bar', 
                    'name': 'New/Re - Downloads'
            }],
            'layout': {
                'yaxis': {
                    'automargin': True
                }
            }
        }
    else:
        new_re_downloads_chart = {}
    return allCampaigns, conversion_rate, ttr, cpa, cpt, installs, orgId
def get_layout(client, appId):
    print("PLOTLY")
    client = "client"
    appId = "id"
    user_id = client
    current_asa_account_id = appId
    campaing_frames = generate_report(client, appId)
    company_name ="THE COMPANY"
    orgs = {'orgName': "THEORG", 'orgId': campaing_frames[6]}
    layout = html.Div(
        [
            dcc.Store(id="aggregate_data"),
            # empty Div to trigger javascript file for graph resizing
            html.Div(id="output-clientside"),
            html.Div(
                [
                    html.Div(
                        [
                            html.Img(
                                src=app.get_asset_url("logo.png"),
                                id="plotly-image",
                                style={
                                    "height": "60px",
                                    "width": "auto",
                                    "margin-bottom": "25px",
                                },
                            )
                        ],
                        className="one-third column",
                    ),
                    html.Div(
                        [
                            html.Div(
                                [
                                    html.H3(
                                        client,
                                        style={"margin-bottom": "0px"},
                                    ),
                                    html.H5(
                                        company_name, style={"margin-top": "0px"}
                                    )
                                ]
                            )
                        ],
                        className="one-half column",
                        id="title",
                    ),
                ],
                id="header",
                className="row flex-display",
                style={"margin-bottom": "25px"},
            ),
            html.Div(
                [
                    html.Div(
                        [
                            html.P("Choose an Organization (Campaign Group):"),
                            dcc.Dropdown(
                                options= [{'label':org[0], 'value': org[1]} for org in orgs],
                                ##value= orgs[0]['orgId'],
                                value= campaing_frames[6],
                                searchable=False,
                                id='org-picker-dropdown'
                            ),
                            html.P("Report Date Range:"),
                            dcc.DatePickerRange(
                                id='my-date-picker-range',
                                min_date_allowed=datetime(2010, 1, 1),
                                max_date_allowed=datetime.now().date(),
                                initial_visible_month=get_last_month_start(),
                                # initialize as past 30 days
                                start_date= datetime.now().date() - relativedelta(days=30), # get_last_month_start(),
                                end_date= datetime.now().date() # get_last_month_end()
                            ),
                        ],
                        className="pretty_container",
                        id="cross-filter-options",
                    ),
                    html.Div(
                        [
                            html.Div(
                                [
                                    html.Div(
                                        [html.H6(id="conversion_rate_text"), html.P("Conversion Rate")],
                                        id="conversion_rate_card",
                                        className="mini_container",
                                    ),
                                    html.Div(
                                        [html.H6(id="ttr_text"), html.P("TTR")],
                                        id="ttr_card",
                                        className="mini_container",
                                    ),
                                    html.Div(
                                        [html.H6(id="cpa_text"), html.P("CPI")],
                                        id="oicpa_cardl",
                                        className="mini_container",
                                    ),
                                    html.Div(
                                        [html.H6(id="cpt_text"), html.P("CPT")],
                                        id="cpt_card",
                                        className="mini_container",
                                    ),
                                    html.Div(
                                        [html.H6(id="installs_text"), html.P("Total Installs")],
                                        id="installs_card",
                                        className="mini_container",
                                    ),
                                    
                                ],
                                id="info-container",
                                className="row container-display",
                            ),
                        ],
                        id="right-column",
                        className="container one-half column",
                    ),
                    
                ],
                className="row flex-display",
            ),

            html.Div(
                [dcc.Graph(id="installs_time_series_chart")], 
                id="installs_time_series_chart_container",
                className="pretty_container four column",
            ),

            html.Div(
                [dcc.Graph(id="cpi_time_series_chart")], 
                id="cpi_time_series_chart_container",
                className="pretty_container four column",
            ),

            html.Div(
                [dcc.Graph(id="new_re_downloads_chart")], 
                id="new_re_downloads_chart_container",
                className="pretty_container four column",
            ),

                    
        ],
        id="mainContainer",
        style={"display": "flex", "flex-direction": "column"},
    )

    return layout
 

if __name__ == '__main__':
    get_layout("aaa", "sss")

The full error:

Traceback (most recent call last):
  File "/home/computer/Documents/app/report.py", line 522, in <module>
    get_layout("aaa", "sss")
  File "/home/computer/Documents/app/report.py", line 373, in get_layout
    campaing_frames = generate_report(client, appId)
  File "/home/computer/Documents/app/ENV/lib/python3.8/site-packages/dash/dash.py", line 1004, in add_context
    output_spec = kwargs.pop("outputs_list")
KeyError: 'outputs_list'

To add context of what is returned from allCampaigns = get_campaigns(client, appId, orgId, start_date, end_date)

a_campaign = {"campaignName": row.campaign.name, "campaignId": row.campaign.id, 
                "clicks": row.metrics.clicks, "conversions": row.metrics.conversions,
                "costPerClick": row.metrics.average_cpc, "costPerConversion": costPerConv}

ga_campaign is then turned into a dataframe: return ga_dataFrame = pd.DataFrame([ga_campaign])

Is there something wrong with how I set up the callback? Is this a data issue from generate_report(client, appId) ?

Hi @feners4 welcome to the forum! Which version of Dash are you using? Prior to dash 1.15 (released in September) you had to pass Outputs and Inputs in lists. If this does not solve your issue, please try to reproduce the problem in a smaller standalone app so that we can investigate.