Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

[BUG] Callbacks still double-register with uvicorn `--reload` when an explicit `name` is passed to `Dash()` (incomplete fix for #3818 / #3883)

Abierto
#3,912 1 comentario 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
55/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Tranquilo
Stack tecnológico
fastapi, python
Área
backend, devtools

Línea de trabajo

Comienza en dash/_utils.py, en alias_main_module, y reproduce el problema con la app proporcionada con nombre explícito y la configuración de recarga de uvicorn. Sigue cómo el worker de recarga importa el servidor y registra los callbacks; se considera terminado cuando la salida de dependencias contiene cada callback una sola vez para nombres explícitos y patrones de fábrica de apps, sin romper el comportamiento existente de main.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

enhancement P3 size: 10+

Summary

Thanks for the fix! This is a follow up issue from #3818 . PR #3883 (released in 4.4.1) fixes the double-registration reported in #3818 but only for the exact idiom app = Dash(__name__) written at the top level of the entry-point file.

The fix (alias_main_module) keys entirely on the app's resolved name being "__main__" or "__mp_main__". As soon as Dash() receives any other name — a literal string, or Dash(__name__) when the app is built inside a package / app-factory (where __name__ is the module name) — the alias no-ops, the module is executed twice in the reload worker, and every callback is registered twice. The renderer then throws:

Duplicate callback outputs
Output 0 (output.children) is already in use.

Environment

  • dash 4.4.1 (dash[fastapi])
  • uvicorn (standard), reload=True
  • Python 3.10, Linux

Minimal reproduction

# repro.py
from dash import Dash, html, dcc, callback, Output, Input

# BUG TRIGGER: any explicit name that is not "__main__"/"__mp_main__".
# Using Dash(__name__) here (top level) works; Dash("myapp") does not.
app = Dash("myapp", backend="fastapi")
app.layout = html.Div([dcc.Input(id="input", value="Hello"), html.Div(id="output")])

@callback(Output("output", "children"), Input("input", "value"))
def update(value):
    return f"You typed: {value}"

app.enable_dev_tools(debug=True, dev_tools_hot_reload=True)
server = app.server

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("repro:server", host="127.0.0.1", port=8050, reload=True)
python3 repro.py
curl -s http://127.0.0.1:8050/_dash-dependencies | grep -o '"output.children"' | wc -l
# -> 2   (expected 1)

Open the page in a browser and the console shows Duplicate callback outputs.


Constructing the app inside a package with Dash(__name__) also reproduces it, because __name__ is the package name, not __main__, in this case -- __name__ == "app_factory":

  • app_factory.py:
from dash import Dash, html, dcc, callback, Output, Input
class AppBuilder:
    def __init__(self):
        self.app = Dash(__name__, backend="fastapi")
        self.app.layout = html.Div([
            html.H1("Reload double-register demo (factory)"),
            dcc.Input(id="input", value="Hello"),
            html.Div(id="output"),
        ])

        @callback(Output("output", "children"), Input("input", "value"))
        def update(value):
            return f"You typed: {value}"

    def setup(self):
        self.app.enable_dev_tools(debug=True, dev_tools_hot_reload=True)
        return self.app.server
  • main.py:
if __name__ != "__main__":
    from app_factory import AppBuilder
    server = AppBuilder().setup()

if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:server", host="127.0.0.1", port=8050, reload=True)

Root Vause

dash/_utils.py:

def alias_main_module(caller_name: str) -> None:
    if caller_name not in ("__main__", "__mp_main__"):
        return
    ...

alias_main_module only aliases the running module into sys.modules when caller_name is exactly "__main__"/"__mp_main__". Passing an explicit name (or building the app anywhere other than the entry module's top level) makes caller_name something else, so the alias is skipped, the "main:server" import string re-executes the file, and the callbacks register a second time.

This means the fix effectively only covers the single-file app = Dash(__name__) tutorial layout, and misses the very common app-factory / class-based / explicitly-named app patterns.

Current Workaround

# Skip the reload worker's __mp_main__ spawn re-exec so callbacks are registered exactly once.
if __name__ not in ("__main__", "__mp_main__"):
    server = build_app()

Works temporarily but idk if that will break in any future releases.

Lenguaje dominante
Python
Estrellas
24.4k
Forks
2.3k
Merge medio
1 d 21 h
PR fusionados (30 d)
19

Guía de contribución

Abrir la guía de contribución

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de plotly/dash

Todos los issues de plotly/dash

Issues similares

Más issues de Python

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.