Is app.validation_layout working with dynamic layouts in Multipage dash web app setup?

Hi Dash Community,

I’m experiencing an issue where app.validation_layout doesn’t prevent callback validation errors when using dynamic layouts with the Pages module in Dash 3.1.1.

Problem Description

According to the documentation, app.validation_layout should allow us to define all possible components to avoid callback validation errors in multi-page apps. However, this doesn’t seem to work with dynamic layouts in the Pages module.

Minimal Reproducible Example - see the code at the end.

Expected Behavior
Based on the documentation, defining app.validation_layout with all possible components should prevent callback validation errors, even for components that are conditionally rendered.

Actual Behavior
Despite defining all components in app.validation_layout, I still get this error:

*Attempting to connect a callback Output item to component: “output-evening” *
*but no components with that id exist in the layout. If you are assigning *
*callbacks to components that are generated by other callbacks (and therefore *
*not in the initial layout), you can suppress this exception by setting *
suppress_callback_exceptions=True.

Current Workaround
The only solution is to use suppress_callback_exceptions=True, but according to the documentation, app.validation_layout should make this unnecessary.

Questions
Is this expected behavior with the Pages module and dynamic layouts?
Is app.validation_layout supposed to work differently with Pages than with single-file apps?
Should the documentation be updated to clarify this limitation?
Environment
Dash: 3.1.1
Python: 3.13
OS: Windows 11
Any insights would be greatly appreciated!

  1. app.py
from dash import Dash, html, dcc, page_container

# Initialize the app with pages module
app = Dash(__name__, use_pages=True)

# Define the main layout
app.layout = html.Div([
    html.H1("Welcome to Our App"),
    dcc.Link("Page 1", href="/page1"),
    html.Br(),
    dcc.Link("Page 2", href="/page2"),
    html.Hr(),
    page_container
])

# Create a validation layout with ALL possible components
app.validation_layout = html.Div([
    # Main app components
    app.layout,
    
    # Morning layout components
    html.Div([
        html.H3("Morning Layout"),
        dcc.Input(id="input-morning", type="text"),
        html.Div(id="output-morning")
    ]),
    
    # Evening layout components
    html.Div([
        html.H3("Evening Layout"),
        dcc.Dropdown(id="dropdown-evening", options=['Tea', 'Coffee']),
        html.Div(id="output-evening")
    ]),

    html.Div([
        html.H2("Welcome to Page 1"),
        dcc.Input(id="input-p1", placeholder="Enter something...", type="text"),
        html.Div(id="output-p1")
    ]),
])

if __name__ == '__main__':
    app.run(debug=True)
  1. pages/page1.py
from dash import register_page, html, dcc, Input, Output, callback

register_page(__name__, path="/page1", name="Page 1")

layout = html.Div([
    html.H2("Welcome to Page 1"),
    dcc.Input(id="input-p1", placeholder="Enter something...", type="text"),
    html.Div(id="output-p1")
])

@callback(Output("output-p1", "children"), Input("input-p1", "value"))
def update_output(value):
    return f"You entered: {value}" if value else ""
  1. pages/page2.py - dynamic layout
from dash import register_page, html, dcc, Input, Output, callback
import datetime

register_page(__name__, path="/page2", name="Page 2")

def layout():
    # Dynamic layout logic based on time of day
    hour = datetime.datetime.now().hour
    if hour < 12:
        return html.Div([
            html.H3("Morning Layout"),
            dcc.Input(id="input-morning", type="text", placeholder="Good morning!"),
            html.Div(id="output-morning")
        ])
    else:
        return html.Div([
            html.H3("Evening Layout"),
            dcc.Dropdown(['Tea', 'Coffee'], id="dropdown-evening", placeholder="Choose your drink"),
            html.Div(id="output-evening")
        ])

@callback(Output("output-morning", "children"), Input("input-morning", "value"))
def handle_morning(val):
    return f"Rise and shine: {val}" if val else ""

@callback(Output("output-evening", "children"), Input("dropdown-evening", "value"))
def handle_evening(drink):
    return f"Unwinding with: {drink}" if drink else ""