Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When callback exceptions are supressed, if an Input or State references an ID that doesn't exist at callback trigger, then an front-end exception is thrown #57

Closed
chriddyp opened this issue Jun 21, 2018 · 5 comments

Comments

@chriddyp
Copy link
Member

No description provided.

@rmarren1
Copy link
Contributor

More details:

when app.config['suppress_callback_exceptions'] = False, dash validates all callbacks when the application is launched and throws a NonExistantIdException here if the initial state of the layout does not include an id used in either the Input, Output, or State of a callback.

E.g.,

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

app = dash.Dash()
app.layout = html.Div([
    html.Button(id='button', children='click'),
    html.P(id='output')
])

@app.callback(Output('output', 'children'),
              [Input('button', 'n_clicks')],
              [State('buttoN', 'n_clicks')])
def put_n_clicks(n_clicks, n_clicks_state):
    if n_clicks:
        return n_clicks
    return 0

app.run_server(debug=True)

-->

dash.exceptions.NonExistantIdException: 
Attempting to assign a callback to the
component with the id "buttoN" but no
components with id "buttoN" exist in the
app's layout.


Here is a list of IDs in layout:
['button', 'output']

This exception would be raised if a user includes a callback using an id of a component that does not exist in the initial state, but is dynamically generated by other callbacks.

For example, an exception is raised in this example:

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

app = dash.Dash()
app.layout = html.Div([
    html.Button(id='button', children='click'),
    html.Div(id='output-div-holder'),
    html.Div(id='output-paragraph')
])

@app.callback(Output('output-div-holder', 'children'),
              [Input('button', 'n_clicks')])
def put_n_clicks(n_clicks):
    return html.Div(children=n_clicks, id='output-div') if n_clicks else 'None'

@app.callback(Output('output-paragraph', 'children'),
              [Input('output-div', 'children')])
def put_child(child):
    return child

because the second callback has an Input for the id 'output-div', but that component does not exist in the initial state (it is generated once the user clicks the button).

To fix this, a user may specify app.config['suppress_callback_exceptions'] = True to let their application run without breaking. Adding that line to the above program makes everything work:

image -->
image

Doing this, however, puts you in debugging hell for large applications since any time you include a callback which has 1. an id which will never exist in the application (you mis-spelled it for example) or 2. an id for a component which does exist in the layout at the time that another Input triggers the callback, you will get nothing but an unhelpful front-end exception:
image

@rmarren1 rmarren1 changed the title if a State is referencing an ID that doesn't exist, then an front-end exception is thrown When app.config['suppress_callback_exceptions'] = True, if a Input or State in a callback is referencing an ID that doesn't exist when the callback is triggered, then an front-end exception is thrown Jul 13, 2018
@rmarren1 rmarren1 changed the title When app.config['suppress_callback_exceptions'] = True, if a Input or State in a callback is referencing an ID that doesn't exist when the callback is triggered, then an front-end exception is thrown When callback exceptions are supressed, if a Input or State in a callback is referencing an ID that doesn't exist when the callback is triggered, then an front-end exception is thrown Jul 13, 2018
@rmarren1 rmarren1 changed the title When callback exceptions are supressed, if a Input or State in a callback is referencing an ID that doesn't exist when the callback is triggered, then an front-end exception is thrown When callback exceptions are supressed, if an Input or State references an ID that doesn't exist at callback trigger, then an front-end exception is thrown Jul 13, 2018
@rmarren1
Copy link
Contributor

It does not look like app.layout updates in sync with the application front-end, which means it is unlikely we can dynamically check this before each callback and throw a back-end exception.

It appears that the exception is thrown from here. I think the quickest patch right now is just to throw a 'nice' exception there telling the user the bad id and the set of currently available ids.

@chriddyp
Copy link
Member Author

It does not look like app.layout updates in sync with the application front-end, which means it is unlikely we can dynamically check this before each callback and throw a back-end exception.
It appears that the exception is thrown from here. I think the quickest patch right now is just to throw a 'nice' exception there telling the user the bad id and the set of currently available ids.

Yeah, a good exception would go a long way for me. Ultimately, I think that our solution will have to be propogating these error messages from the JS context up to the browser context (in dev-mode) with some type of persistent notifications. That's a much larger project that we should probably discuss in a separate issue

@rmarren1
Copy link
Contributor

Sounds good, I'll make a quick fix with a better exception for now

@varunsampat30
Copy link

Hello, I am currently working on a Dash project and came across the same issue, and completely understand why suppressing the warning is bad practise. I followed the thread attached at the end of page (A proposed alternative ...) but didn't really understand it. What is the proposed solution?

Thanks in advance!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants