plotly / plotly/dash

Component with duplicate id doesn't raise a warning if created in a callback - overwrites the callback(s) the first component was part of

Open
#3,420 0 comments 0 reactions 1 assignee View on GitHub

@T4rk1n is already working on this.

Since Sep 9, 2025.

bug cs P1
Dominant language
Python
Stars
24.4k
Forks
2.3k
Avg merge
2d 7h
Merged PRs (30d)
13

Description

Description of the issue

https://github.com/user-attachments/assets/821b9dd9-acc1-44b6-a9b5-c52a22778149

  • The issue happens both if the affected callback (the one that uses the "duplicated" id as Input, Output or State) is defined with @app.callback or @dash.callback.
  • suppress_callback_exceptions=True is not set in app = Dash(...).
  • The rest of the callbacks (both defined with @app.callback and @dash.callback ) keep working after the component generation (not shown in the video).
  • The component that the affected callback uses is the newest one.
  • If, after generating the second component, I do document.getElementById in the Console, the component that's identified is the one that appears first in the html.

Case 1: sample code (original button is first)
Image

Case 2: new button is first
Image

Expected behavior

Component id validation should also happen when new components are added to the layout. An error like this should be shown in the debug menu or the logs:

dash.exceptions.DuplicateIdError: Duplicate component id found in the initial layout: `b3`

Code to replicate the issue

dash==3.2.0

import dash
from dash import dcc, html, Input, Output, State, callback, ctx

app = dash.Dash(__name__)

app.layout = html.Div([
    html.H3("callback 1: @app.callback, output=div1"),
    html.Button(id="b1", children="Trigger callback 1"),
    html.Div(id="div1", children="callback 1 not triggered yet"),
    ####
    html.H3("callback 2: @callback, output=div2"),
    html.Button(id="b2", children="Trigger callback 2"),
    html.Div(id="div2", children="callback 2 not triggered yet"),
    ###
    html.H3("callback 3: @app.callback, output=div3"),
    html.Button(id="b3", children="Trigger callback 3 (initial n_clicks=20)", n_clicks=20),
    html.Div(id="div3", children="callback 3 not triggered yet"),
    ####
    html.Br(),
    html.Button(id="b4", children="Generate component with duplicate id (b3)"),
    html.Br(),
    html.Div(id="div4")
])

@app.callback(
    Output("div1", "children"),
    Input("b1", "n_clicks"),
    prevent_initial_call=True
)
def update_div1_with_b1(b1):
    return f"Callback 1 triggered by {ctx.triggered_id} and {b1} clicks"

@callback(
    Output("div2", "children"),
    Input("b2", "n_clicks"),
    prevent_initial_call=True
)
def update_div1_with_b2(b2):
    return f"Callback 2 triggered by {ctx.triggered_id} and {b2} clicks"

@callback(
    Output("div3", "children"),
    Input("b3", "n_clicks"),
    prevent_initial_call=True
)
def update_div3(b3):
    return f"Callback 3 triggered by {ctx.triggered_id} and {b3} clicks"

@callback(
    Output("div4", "children"),
    Input("b4", "n_clicks"),
    prevent_initial_call=True
)
def update_div4(b4):
    return html.Button(id="b3", children="Button with duplicate id (b3)", n_clicks=0),

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.