# Execution flow of a composed app

!!! abstract “”

    How data flows through a composed pipeline, step by step.

Consider two apps composed into a pipeline:

```python { notest } from scinexus import define_app

@define_app(app_type=“loader”) def read_json(path: str) -> dict: import json

    with open(path) as f:
        return json.load(f)

@define_app def validate(data: dict, required_field: str) -> dict: if required_field not in data: raise ValueError(f”missing {required_field!r} field”) return data

app = read_json() + validate(required_field=“name”)

    Composing with `+` creates a new app where `validate` is the outermost app and `read_json` is stored as its `.input` attribute. When you call `app(filepath)`, execution begins at the outermost app and works inward.

    ## The execution flow when you call `app(filepath)`

    ```mermaid
    flowchart TD
        entry["Executes scinexus __call__(val)"] --> none{val is None?}
        none -- yes --> nc_none[create and return NotCompleted ERROR, recording current app as origin]
        none -- no --> nc{val is NotCompleted?}
        nc -- yes --> nc_return[returns same NotCompleted]
        nc -- no --> has_input{has an input app?}
        has_input -- yes --> call_input["call input(val), which enters the top of this chart"]
        call_input --> input_nc{result is NotCompleted?}
        input_nc -- yes --> nc_input[return same NotCompleted]
        input_nc -- no --> type_check
        has_input -- no --> type_check{val type is valid for self}
        type_check -- fail --> nc_type[create and return NotCompleted ERROR]
        type_check -- pass --> main["main(val)"]
        main -- exception --> nc_main[NotCompleted ERROR]
        main -- success --> result["return result (which may be NotCompleted FAIL)"]

        classDef errorNode fill:#fde0c8,stroke:#333
        classDef successNode fill:#c8e0fd,stroke:#333
        class nc_none,nc_return,nc_input,nc_type,nc_main errorNode
        class result successNode

This is the same sequence for every composed app, regardless of pipeline length. Each app in the chain runs the same `__call__` checks, so `NotCompleted` propagation and exception handling are consistent throughout. See Runtime type checking for details on how type validation works and how to disable it.