Duplicate callback outputs don't work even with allow_duplicate=True

Hello,
I have the following callbacks:

@app.callback(
        Output('mail-modal', "is_open", allow_duplicate=True),
        Output(modal_id, "is_open"),
        Input('info-mailto-person', 'n_clicks'),
        prevent_initial_call=True
    )
    def toggle_mail_modal(mailto_clicks, is_open):
        if not mailto_clicks:
            raise PreventUpdate
        return True, False


@app.callback(
    Output('mail-modal', "is_open"),
    Output('email-is-sent-alert', 'is_open'),
    Output('modal-form-email-feedback', 'children'),
    Output('modal-form-subject-feedback', 'children'),
    Output('modal-form-text-feedback', 'children'),
    Output('modal-form-general-feedback', 'children'),
    Input('modal-send-email-button', 'n_clicks'),
    State('modal-form-email', 'value'),
    State('modal-form-subject', 'value'),
    State('modal-form-text', 'value'),
    prevent_initial_call=True
)
def send_email(clicks, email, subject, text):
   # some code

even with specified allow_duplicate=True, i get an error:

"In the callback for output(s):
  mail-modal.is_open@5d812f45153073fc6b2e0d2b62389aa2
Output 0 (mail-modal.is_open@5d812f45153073fc6b2e0d2b62389aa2) 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 could try to combine the callbacks into one, but i don’t like this idea, so maybe someone know at least why allow_duplicate doesn’t work?

Hi, what’s the value of this variable?

What is the allow_duplicate=True for? Doesn’t that their an error?

boolean, true or false

allow_duplicate is for allow several callbacks with the same output, what i actually did

I was referring to the variable modal_id

I was referring to the allow_duplicate=True outside of any Output()

Try removing one of the two allow_duplicate

Even without it, doesn’t work, i just tried it, because saw it as a solution somewhere in stackoverflow as i remember

Regarding this, i tried all combinations, doesn’t work

It is a string, i create callbacks as batch and pass modal_id as parameter, if you think that modal_id can contain ‘mail-modal’, then no, i’ve checked it.

Hello @Vladner,

I think this may be because you have an allow_duplicate declaration in the callback itself, when it should just be in the prop that you are allowing a duplicate.


@app.callback(
        Output('mail-modal', "is_open", allow_duplicate=True),
        Output(modal_id, "is_open"),
        Input('info-mailto-person', 'n_clicks'),
 #        allow_duplicate=True,
        prevent_initial_call=True
    )
    def toggle_mail_modal(mailto_clicks, is_open):
        if not mailto_clicks:
            raise PreventUpdate
        return True, False


@app.callback(
    Output('mail-modal', "is_open", allow_duplicate=True),
    Output('email-is-sent-alert', 'is_open'),
    Output('modal-form-email-feedback', 'children'),
    Output('modal-form-subject-feedback', 'children'),
    Output('modal-form-text-feedback', 'children'),
    Output('modal-form-general-feedback', 'children'),
    Input('modal-send-email-button', 'n_clicks'),
    State('modal-form-email', 'value'),
    State('modal-form-subject', 'value'),
    State('modal-form-text', 'value'),
 # this doesn’t do anything and probably an error   allow_duplicate=True,
    prevent_initial_call=True
)
def send_email(clicks, email, subject, text):
   # some code

Ok, i removed it from the first message, since it is not a root issue, because even without allow_duplicate in the callback itself it doesn’t work

What about the marked line? What is the value of the variable modal_id ?

It is a string, i create callbacks as batch and pass modal_id as parameter, if you think that modal_id can contain ‘mail-modal’, then no, i’ve checked it. it doesn’t have certain value, but all possible values is a string.

Example of the values:
‘prec_modal_r1c1’
‘prec_modal_r1c2’
‘prec_modal_r0c1’
‘prec_modal_r0c2’

I’d check your code for ‘mail-modal’ in outputs, and make sure there isnt one hiding.

Also… if these definitions happen to be inside a function call, this would also put duplicates.

If you mean there is no ‘mail-modal’ anymore, i’ve already checked it.

sorry, didn’t get you, could you please clarify this point?

Full code, maybe there is something affect as well, but i don’t even think about it:

def get_info_callback(app, button_id, modal_id, close_id):
    @app.callback(
        [Output(modal_id, "is_open", allow_duplicate=True)],
        [Input(button_id, "n_clicks"), Input(close_id, "n_clicks")],
        [State(modal_id, "is_open")],
        prevent_initial_call=True
    )
    def toggle_info_modal(n1, n2, is_open):
        if not n1 or n2:
            raise PreventUpdate
        if n1 or n2:
            return not is_open
        return is_open

    @app.callback(
        [Output('mail-modal', 'is_open'),
        Output(modal_id, "is_open")],
        Input('info-mailto-person', 'n_clicks'),
        prevent_initial_call=True
    )
    def toggle_mail_modal(mailto_clicks, is_open):
        if not mailto_clicks:
            raise PreventUpdate
        return True, False


def create_general_callbacks(app):
    @app.callback(
        Output('mail-modal', 'is_open', allow_duplicate=True),
        Output('email-is-sent-alert', 'is_open'),
        Output('modal-form-email-feedback', 'children'),
        Output('modal-form-subject-feedback', 'children'),
        Output('modal-form-text-feedback', 'children'),
        Output('modal-form-general-feedback', 'children'),
        Input('modal-send-email-button', 'n_clicks'),
        State('modal-form-email', 'value'),
        State('modal-form-subject', 'value'),
        State('modal-form-text', 'value'),
        prevent_initial_call=True
    )
    def send_email(clicks, email, subject, text):
        is_open = True
        addr = {core_endpoints.packages.app_config.ms_identity_web.id_data._token_cache.Account.username}

        regex = re.compile(r'([A-Za-z0-9]+[.-_])*[A-Za-z0-9]+@[A-Za-z0-9-]+(\.[A-Z|a-z]{2,})+')
        not_valid_email = not email or not re.fullmatch(regex, email)

        is_subject = bool(subject)
        is_text = bool(text)

        if any([not_valid_email, not is_subject, not is_text]):
            return is_open, False, not_valid_email, not is_subject, not is_text, ""

        try:
            mail_manager.mail_send(to=email, from_addr=addr, subject=subject, body=text, mime_type='plain')
        except Exception as ve:
            return is_open, False, not_valid_email, is_subject, is_text, str(ve)

        return False, True, not_valid_email, is_subject, is_text, ""

create_general_callbacks is called before get_info_callback

I bet that your layout is calling both of these twice while the app is loading.

Where are you calling these functions?

I’ve added prints to check that case, but no, only once.

In the main app.py file:

create_general_callbacks(app)
precipitation_callback(app)

Precipitation/prec_layout.py fille:

def precipitation_callback(app):
    precipitation_callback_init(app, 'button_monthly_id', 'modal_monthly_id', 'close_monthly_id')

def precipitation_callback_init(app, button_monthly_id=None, modal_monthly_id=None, close_monthly_id=None):
    if button_monthly_id is not None and modal_monthly_id is not None and close_monthly_id is not None:
        get_info_callback(app, button_monthly_id, modal_monthly_id, close_monthly_id)

My recommendation is to bring all your stuff into one place, dont split it out until you get the app working the way that you want it to.

Then, you go from there.

Since you are piecemealing it out to us, it is impossible to narrow down where you are causing the issue. From what we see, there shouldnt be any issue from it.

You can save github and share a link to view your entire repo.

Or create an example app that spins up the way that you are wanting and share that, if the issue still remains.

1 Like

I expected that answer, the problem i cannot share the full code, so i tried just provide pieces which are possible lead to the issue, but i understand that sometimes it is not possible to indicate the problem when you don’t see the whole picture.

I will try to create the small demo app, maybe even during creation of that demo app i will find out what is wrong. Thanks for the answers!

2 Likes

Good luck, I am thinking as you make an example app, you’ll find where you are mis stepping.

2 Likes

The problem was in the Input, not in Output:

@app.callback(
        [Output('mail-modal', 'is_open'),
        Output(modal_id, "is_open")],
        Input('info-mailto-person', 'n_clicks'),
        prevent_initial_call=True
    )
    def toggle_mail_modal(mailto_clicks, is_open):
        if not mailto_clicks:
            raise PreventUpdate
        return True, False

actually i create this callback in some kind of a loop and when i changed

`Input(‘info-mailto-person’, ‘n_clicks’)
to
Input(f’info-mailto-person-{modal_id}', ‘n_clicks’)
it started to work, so, as i understand it is not possible to create the callback with duplicate outputs and duplicate inputs as well.

Maybe i missed something from the doc, because there is the following section: Updating the Same Output From Different Inputs, but i treated it as could be different could be not, from my point of view it was not obvious.

This was something that we couldnt see. :smiley: Glad you got it figured out.

And yes, Dash serializes the component inputs to be a unique identified, and only the inputs, not States.

A trick you can do it so include something like the id of the component, that way it is always will be different. :smiley:

Ok, i understood, i should clarify points in a more clear way, because i thought it was clear with the reply above:

It is a string, i create callbacks as batch and pass modal_id as parameter, if you think that modal_id can contain ‘mail-modal’, then no, i’ve checked it. it doesn’t have certain value, but all possible values is a string.

Example of the values:
‘prec_modal_r1c1’
‘prec_modal_r1c2’
‘prec_modal_r0c1’
‘prec_modal_r0c2’

but maybe i did because i didn’t even thought about Inputs, i knew that the id in the layout should be unique, but didn’t know that it was not possible to use duplicate callbacks and duplicate inputs.

Thanks for the answers anyway!