Textualize/textual · error · AppFail

Unable to find app in {lib!r}, try specifying app with "foo.

Error message

Unable to find app in {lib!r}, try specifying app with "foo.py:app"

What it means

Textual's import_app() raises this when a file is loaded without an explicit app name and it contains no module-level `app` variable, no App instance, and no App subclass other than textual.app.App itself. Textual scans the file's globals for anything that is an App instance or an App subclass; an empty result means the file simply does not expose a Textual app at module scope. The fix suggested by the message itself is to use the `file:app` syntax.

Source

Thrown at src/textual/_import_app.py:97

            if "app" in global_vars:
                # App exists, lets use that
                try:
                    app = global_vars["app"]
                except KeyError:
                    raise AppFail(f"App {name!r} not found in {lib!r}")
            else:
                # Find an App class or instance that is *not* the base class
                apps = [
                    value
                    for value in global_vars.values()
                    if (
                        isinstance(value, App)
                        or (inspect.isclass(value) and issubclass(value, App))
                        and value is not App
                    )
                ]
                if not apps:
                    raise AppFail(
                        f'Unable to find app in {lib!r}, try specifying app with "foo.py:app"'
                    )
                if len(apps) > 1:
                    raise AppFail(
                        f'Multiple apps found {lib!r}, try specifying app with "foo.py:app"'
                    )
                app = apps[0]
        app._BASE_PATH = path

    else:
        # Assuming the user wants to import the file
        sys.path.append("")
        try:
            module = importlib.import_module(lib)
        except ImportError as error:
            raise AppFail(str(error))

        find_app = name or "app"

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Specify the app explicitly with path:name syntax: `textual run foo.py:MyApp`
  2. Move the App subclass or instance to module level in the target file
  3. Point the command at the file that actually defines the app, not a helper module
  4. Import the app into the entry file so it becomes a global there

Example fix

# before
# myapp.py
def make_app():
    class MyApp(App): ...
    return MyApp()
# CLI: textual run myapp.py  -> AppFail

# after
# myapp.py
class MyApp(App): ...
app = MyApp()
# CLI: textual run myapp.py:app
Defensive patterns

Strategy: validation

Validate before calling

import runpy, inspect
from textual.app import App

def discover_apps(path: str) -> list:
    g = runpy.run_path(path)
    return [v for v in g.values()
            if isinstance(v, App) or (inspect.isclass(v) and issubclass(v, App) and v is not App)]

# assert len(discover_apps("foo.py")) >= 1 before invoking textual

Try / catch

try:
    app = import_app("foo.py")
except AppFail as e:
    # fall back to explicit naming
    app = import_app("foo.py:MyApp")

Prevention

When it happens

Trigger: Running `textual run foo.py` (or take_svg_screenshot on it) when foo.py only defines helper functions or imports App without subclassing it; the App subclass is nested inside another class or function; the file defines the app under `if __name__ == "__main__":` only; the file is a library module with no app.

Common situations: Pointing the CLI at the wrong file in a multi-file project; copy-pasted examples where the app class is defined in an imported module rather than the entry file; apps built inside factory functions like `def create_app(): return App()`; using an installed package name instead of a file path, so the scanned globals are the package's __init__.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/7e04c02168e7b836. Report an issue: GitHub.