Dash JS Errors - Callback error updating

I have a Dash App running inside a Flask App. I am seeing a bunch of JS errors in the console after upgrading dash to 2.7.1

Uncaught (in promise) Error: A listener indicated an asynchronous response by returning true, but the message channel closed before a response was received

{message: 'Callback error updating ..map-deal.figure...comps-…children...msa-prop-store.data...geo-store.data..', html: '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final/…ded or there is an error in the application.</p>\n'}
html
: 
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>500 Internal Server Error</title>\n<h1>Internal Server Error</h1>\n<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>\n"
message
: 
"Callback error updating ..map.figure..."


Uncaught (in promise) Error: There is already a source with this ID

at r.addSource (async-plotlyjs.js:2:1020888)
    at i.addSource (async-plotlyjs.js:2:1219363)
    at l.addSource (async-plotlyjs.js:2:2988732)
    at async-plotlyjs.js:2:2989736
    at h (async-plotlyjs.js:2:2989770)
    at l.update (async-plotlyjs.js:2:2990100)
    at b.updateData (async-plotlyjs.js:2:2338377)
    at async-plotlyjs.js:2:2336961

error-ss

I do not see any errors in the application logs. What is the error? Any suggestions on where to look / troubleshoot?

Application code:

tab1.py

import dash
from dash import dcc
import pandas as pd

df = pd.DataFrame({
                   'x': [1, 2, 3],
                   'Lat': [37.774322, 37.777035, 37.773033],
                   'Long': [-122.489761, -122.485555, -122.491220]
                 }) 

layout = html.Div(
                   dcc.Graph(id="map"),
                   dcc.Input(id="inp")
                 )

@app.callback(
              Output('map','figure'),
              Input('inp','value')
             )
def fin(val):
    
    # do something

    data = []
    
    data.append({

                                 "type": "scattermapbox",
                                 "lat": df["Lat"],
                                 "lon": df["Long"],
                                 "name": "Location",
                                 "showlegend": False,
                                 "hoverinfo": "text",
                                 "mode": "markers",
                                 "clickmode": "event+select",
                                 "customdata": df.loc[:,cd_cols].values,
                                 "marker": {
                                            "symbol": "circle",
                                            "size": 8,
                                            "opacity": 0.7,
                                            "color": "black"
                                           }
                                 }
                   )

      layout = {

                     "autosize": True,
                     "hovermode": "closest",
                     "mapbox": {

                         "accesstoken": MAPBOX_KEY,
                         "bearing": 0,
                         "center": {
                             "lat": xxx,
                             "lon": xxx
                         },
                         "pitch": 0,
                         "zoom": zoom,
                         "style": "satellite-streets",

                     },

                    
        }

        return ({'data': data, 'layout': layout})

application.py

import dash
import flask
from dash import dcc, html
import dash_bootstrap_components as dbc
import os

# External stylesheets

SANDSTONE = "xxxxx"

external_stylesheets = [
    SANDSTONE,
    {
        'href': 'custom.css',
        'rel': 'stylesheet'
    },
    {
        'href': 'https://use.fontawesome.com/releases/v5.10.2/css/all.css',
        'rel': 'stylesheet'
    }
]

application = dash.Dash(__name__,
                        requests_pathname_prefix='/dashboard/',
                        #serve_locally = False,
                        suppress_callback_exceptions = True,
                        meta_tags=[
                            {"name": "viewport", "content": "width=device-width, initial-scale=1"}
                        ],
                        external_stylesheets=external_stylesheets,
               )


server = application.server

# Title the app.
application.title = "Stroom - Platform Demo"

index.py

# In[32]:

import pandas as pd
import dash
from dash.dependencies import Input, Output, State
from dash import dcc
import dash_bootstrap_components as dbc
from dash import html
#import dash_design_kit as ddk
import plotly as py
from plotly import graph_objs as go
from plotly.graph_objs import *
import flask
from application import application
import os
from tabs import comps, analysis, deals, returns
from pages import home
import traceback

# In[8]:
server = application.server

# App Layout
application.layout = html.Div([

                        # header
                        html.Div([

                            html.Div(

                                html.Img(src='https://ss.s3.us-west-1.amazonaws.com/logo-black.png',height="100%"),
                                style={"float":"right",
                                       "width":"170px",
                                       "height":"100px",
                                       "margin-top":"-84px"
                                       }
                            ),

                            html.Div(

                                [
                                    html.H4("Market Intelligence", style={"textAlign":"center"}),
                                    html.Hr(),
                                    dbc.Nav(
                                        [
                                            dbc.NavLink("Tab1", href="/tab1", active="partial"),
                                            dbc.NavLink("Tab2", href="/tab2", active="partial"),
                                           

                                        ],
                                        vertical=True,
                                        fill=True,
                                        pills=True,
                                    ),
                                ],

                                style = {
                                    "position": "fixed",
                                    "top": 0,
                                    "left": 0,
                                    "bottom": 0,
                                    "width": "10rem",
                                    "padding": "1rem 1rem",
                                    "background-color": "#f8f9fa",
                                },

                            ),

                            dcc.Location(id='url'),

                            html.Div(id='page-content'),

                            # Store component
                            dcc.Store(id="comps-store", storage_type="local"),

                            # Store component for graphs
                            dcc.Store(id="modal-store", storage_type="local"),

                            ],

                        )

])



# Render page content
@application.callback(Output("page-content", "children"),
              [
                Input('url', 'pathname')
              ]
             )
def display_content(pathname):

    print(pathname)

    if pathname in ["/","/dashboard/","/dashboard2"]:
        return tab1.layout

    elif pathname == "/comps":
        return comps.layout

    else:
        return dash.no_update

init.py

from flask import Flask, redirect
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_required
import sys
import os
sys.path.append("..") # Adds higher directory to python modules path.
from werkzeug.middleware.dispatcher import DispatcherMiddleware
from werkzeug.serving import run_simple
from index import application as dashApp

import pymysql
from sqlalchemy import create_engine


database = 'login'

server_auth = Flask(__name__, instance_relative_config=False)

server_auth.config['SECRET_KEY'] = os.environ["pwd"]
server_auth.config['SQLALCHEMY_DATABASE_URI'] = "mysql+pymysql://{}:{}@{}/{}".format(os.environ["user"],os.environ["pwd"],os.environ["host"], database)

# Update this for Production
server_auth.config['TESTING'] = True

# init SQLAlchemy so we can use it later in our models
db = SQLAlchemy(server_auth)

db.init_app(server_auth)

login_manager = LoginManager()
login_manager.login_view = 'auth.login'
login_manager.init_app(server_auth)

from .models import users, init_db
init_db() # created mysql tables

@login_manager.user_loader
def load_user(user_id):
    # since the user_id is just the primary key of our user table, use it in the query for the user
    return users.query.get(int(user_id))

# blueprint for auth routes in our app
from .auth import auth as auth_blueprint
server_auth.register_blueprint(auth_blueprint)

# blueprint for non-auth parts of app
from .main import main as main_blueprint
server_auth.register_blueprint(main_blueprint)

# from .app import appdash as dash_blueprint
# app.register_blueprint(dash_blueprint)
# return server_auth

@server_auth.route('/dashboard')
@login_required
def dashboard():
    return redirect('/dashboard')

app = DispatcherMiddleware(server_auth,
                           {'/dashboard': dashApp.server})


if __name__ == '__main__':
    run_simple('0.0.0.0', 80, app, use_reloader=True, use_debugger=True)
1 Like

Hello @keval,

I’m wondering if maybe this is because you have multiple paths referenced for the same layout, which is also referencing a callback.

What happens if you bring the callback to the index or application level?

Also, have you considered using dash pages instead of the index?

Interesting.

How do you mean using pages instead of index? Are you able to share an example?

My app was working fine, I started encountering the issue with upgrade to dash 2.7.1.

As far as multi-page apps, this should cover it:

Does rolling back to 2.7 make the issues go away?

Yes, the error goes away after running:

Installing collected packages: dash
  Attempting uninstall: dash
    Found existing installation: dash 2.8.1
    Uninstalling dash-2.8.1:
      Successfully uninstalled dash-2.8.1
Successfully installed dash-2.6.2

This error message suggests a communication issue between the listener and the message channel. The problem arises from the internal promisification of sendMessage, allowing you to ‘await’ it. As a result, when you do not specify a callback yourself, one is added internally to ensure the call returns a Promise. Consequently, when you don’t call sendResponse in onMessage, the API interprets it as your error for not using a callback and not providing a response, and reports it accordingly.

Given that the new behavior is causing confusion for nearly everyone, one potential solution could involve not displaying this error when the callback is not specified. However, this approach may lead to confusion among developers who inadvertently forget to call sendResponse inside onMessage when they are still using callbacks, which ideally should be reported, as it has been in the past.

If you see your extension causing this errors - inspect closely all your onMessage listeners. Some of them probably need to start returning promises (marking them as async should be enough).

If still error showing, try disabled all installed extensions in Chrome then you will get a clear console without errors.