Dupilicate Outputs with page container

Hi,
I met an dupilicate issue when change main page element from sub page:

Here is a small example: (sorry I didn’t find a way to do code formatting here)

app.py:

import dash
from dash import Dash, html, dcc

app = Dash(__name__, use_pages=True)

app.layout = html.Div([
    html.H1('Multi-page app with Dash Pages'),
    html.Div(id="page_name"),
    dcc.Location(id='url', refresh=True),
    html.Div([
        html.Div(
            dcc.Link(f"{page['name']} - {page['path']}", href=page["relative_path"])
        ) for page in dash.page_registry.values()
    ]),
    dash.page_container
])

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

archive.py:

import dash
from dash import html, callback, Input, Output


dash.register_page(__name__)

layout = html.Div([
    html.H1('This is our Archive page'),
    html.Div('This is our Archive page content.'),
])

@callback(
    Output("page_name", "children", allow_duplicate=True),
    Input("url", "pathname"),
    prevent_initial_call=True,
)
def update_page_name(url):
    return url

home.py:

import dash
from dash import html, callback, Input, Output

dash.register_page(__name__, path='/')

layout = html.Div([
    html.H1('This is our Home page'),
    html.Div('This is our Home page content.'),
])

@callback(
    Output("page_name", "children", allow_duplicate=True),
    Input("url", "pathname"),
    prevent_initial_call=True,
)
def update_page_name(url):
    return url

In archive.py and home.py there is a callback to change an element in app.layout. But it always cause issue:

Duplicate callback outputs

In the callback for output(s):

page_name.children@b80108fca58ba4aeaa5e8c587a7e4ff4
Output 0 (page_name.children@b80108fca58ba4aeaa5e8c587a7e4ff4) is already in use.
To resolve this, set allow_duplicate=True on
duplicate outputs, or combine the outputs into
one callback function, distinguishing the trigger
by using dash.callback_context if necessary.

Can anyone peovide any suggest to fix that?

Thanks in advance.

Hi @kongyuan
Welcome to the dash community :slightly_smiling_face:

I did a quick edit on your post. You can format code by clicking on the </> in the header when you edit posts.

Or you can just surround the code with three back tics: ```

You have this identical callback in two different files:


@callback(
    Output("page_name", "children", allow_duplicate=True),
    Input("url", "pathname"),
    prevent_initial_call=True,
)
def update_page_name(url):
    return url

If they are exact duplicates in your real app, you can just delete one of the callbacks. But I’m assuming that this is a minimal example for illustration and the two callbacks will be different. In that case, if you include the allow_duplicate=True on one of the callbacks, it should fix the error.

Thanks a lot @AnnMarieW . This really fixed this issue (with 2 pages).Now I add a third page:

test3.py:

import dash
from dash import html, callback, Input, Output

dash.register_page(__name__)

layout = html.Div([
    html.H1('This is our test3 page'),
    html.Div('This is our test3 page content.'),
])

@callback(
    Output("page_name", "children", allow_duplicate=True),
    Input("url", "pathname"),
    prevent_initial_call=True,
)
def update_page_name(url):
    return url```

This error is back:

> Duplicate callback outputs
> 
> In the callback for output(s):
>   page_name.children@b80108fca58ba4aeaa5e8c587a7e4ff4
> Output 0 (page_name.children@b80108fca58ba4aeaa5e8c587a7e4ff4) is already in use.
> To resolve this, set `allow_duplicate=True` on
> duplicate outputs, or combine the outputs into
> one callback function, distinguishing the trigger
> by using `dash.callback_context` if necessary.


I tried both allow_duplicate=True or False but this error always exists. How to fix this issue?

Hello @kongyuan,

For duplicates to be determined, they need to have different inputs for the serialization of a unique id. Since you are reusing the same inputs each time, there is nothing unique to make the serialization process differentiate.

You can add something unique as an unused input from the page if you want to keep it this way. The easiest is an id from the pages layout.

Another thing, since you are always targeting the pathname, bring it out into one callback.

Then, when you switch the pathname just return the response you want to. Something you could do is to add a definition to each page registry of the function that you call on that page, then when the app finishes spinning up, you create a dictionary that maps the functions from the registry to the pathname as a key, the resulting callback would turn into this:

@app.callback(
    Outputs, Inputs
)
def returnPageFunction(inputs)
    func = pageFunctions.get(pathname)
    if func:
        return func()
    return dash.no_update

The dictionary would be set like this:

pageFunctions = {}
for pg in dash.page_registry.values():
    if pg.get(‘pageFunction’):
        pageFunctions[pg[“path”]] = pg.get(‘pageFunction’)

To register the function on the page:

dad.register_page(…, pageFunction=pageFunctionFromPage)

In your case, assuming you are naming every page, you could just register the name in the registry, assuming it will be the name, you could do this:

for pg in dash.pages_registry.values():
    if pg[“path”] == pathname:
        return pg[“name”]

Many thanks @jinnyzor, your advises are valuable!

1 Like