Skip to content

[BUG] dcc.Loading spinner does not trigger when callback Output uses ALL wildcard #3619

Description

@i-murray

Describe your context

dash 4.0.0
dash-bootstrap-components 2.0.4
dash-table 5.0.0
  • OS: Windows 11
  • MS Edge
  • Version 145

Describe the bug

dcc.Loading never displays the loading spinner when a callback's Output uses the ALL wildcard in a pattern-matching ID, e.g.:

Output({"type": "my-graph", "id": ALL, "name": MATCH}, "figure")

The same callback with MATCH or a fully-specified ID works correctly — the spinner appears during the callback execution.

Root cause

In dash-renderer/src/actions/callbacks.ts, loadingOutputs is constructed as:

loadingOutputs=outputs.map(function (out) {
return {
path: getPath(paths, out.id),
property: out.property?.split('@')[0],
id: stringifyId(out.id)
};
});

When the output spec contains ALL, unwrapIfNotMulti returns the resolved outputs as an array (because isMultiValued returns true). This array is pushed into outputs as a single element, producing a nested structure like [[{id, property}, ...]]. When .map() iterates over this, out is the inner array, so out.id is undefined → getPath returns undefined → the loading reducer receives a bogus path → dcc.Loading never matches it → no spinner.

Notably, the same function already uses flatten(outputs) correctly on L829 and L912 when processing the actual response data — the flattening was simply missed for the loading dispatch.

Fix

Change outputs.map(…) to outputs.flat().map(…) on L794 so the nested arrays from multi-valued outputs are flattened before resolving paths:

loadingOutputs=outputs.flat().map(function (out) {
// ...samebody
});

Expected behavior

dcc.Loading should display the loading spinner for callbacks with ALL in the Output, the same as it does for MATCH or fully-specified outputs.

Minimal reproducible example

"""Minimal Dash app to test dcc.Loading with ALL vs specific callback outputs."""importtimeimportdash_bootstrap_componentsasdbcfromdashimportALL, MATCH, Dash, Input, Output, dcc, htmlapp=Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
FIGURE_A= {"data": [{"x": [1, 2, 3], "y": [1, 3, 2]}], "layout": {"title": "Option A"}}
FIGURE_B= {"data": [{"x": [1, 2, 3], "y": [3, 1, 2]}], "layout": {"title": "Option B"}}
RADIO_OPTIONS= [
{"label": "Option A", "value": "a"},
{"label": "Option B", "value": "b"},
]
graph_id_all= {"type": "graph-all", "id": "component", "name": "test"}
graph_id_match= {"type": "graph-match", "id": "component", "name": "test"}
app.layout=html.Div([
html.H3("dcc.Loading test: ALL vs MATCH in Output"),
dbc.Row([
# ALL output — spinner BROKENdbc.Col([
html.H5("ALL in Output (broken)"),
dbc.RadioItems(options=RADIO_OPTIONS, value="a",
id={"type": "radio-all", "id": "component", "name": "test"}, inline=True),
dcc.Loading(
dcc.Graph(id=graph_id_all, figure=FIGURE_A),
type="dot",
overlay_style={"visibility": "visible", "opacity": 0.5, "filter": "blur(2px)"},
),
], width=6),
# MATCH output — spinner WORKSdbc.Col([
html.H5("MATCH in Output (works)"),
dbc.RadioItems(options=RADIO_OPTIONS, value="a",
id={"type": "radio-match", "id": "component", "name": "test"}, inline=True),
dcc.Loading(
dcc.Graph(id=graph_id_match, figure=FIGURE_A),
type="dot",
overlay_style={"visibility": "visible", "opacity": 0.5, "filter": "blur(2px)"},
),
], width=6),
]),
], className="p-3")
@app.callback(Output({"type": "graph-all", "id": ALL, "name": MATCH}, "figure"),Input({"type": "radio-all", "id": ALL, "name": MATCH}, "value"),prevent_initial_call=True,)defupdate_all(values):
time.sleep(2)
return [FIGURE_Aifvalues[0] =="a"elseFIGURE_B]
@app.callback(Output({"type": "graph-match", "id": MATCH, "name": MATCH}, "figure"),Input({"type": "radio-match", "id": MATCH, "name": MATCH}, "value"),prevent_initial_call=True,)defupdate_match(value):
time.sleep(2)
returnFIGURE_Aifvalue=="a"elseFIGURE_Bif__name__=="__main__":
app.run(debug=True, port=8051)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions