Textualize/textual · error · AppFail

App {name!r} not found in {lib!r}

Error message

App {name!r} not found in {lib!r}

What it means

Raised by Textual's import_app() when an app is imported from a Python file (not an installed package) and the name given before the colon (e.g. "foo.py:myapp") does not exist as a global variable in that file. Textual loads the file with runpy and looks up the requested name in the module's global namespace, so a typo or an app that lives inside a function/if-main guard will not be found. The error is wrapped in AppFail, which is what CLI commands like `textual run` and the SVG screenshot tool report.

Source

Thrown at src/textual/_import_app.py:76

    if drive:
        lib = os.path.join(drive, os.sep, lib)

    if lib.endswith(".py") or shebang_python(Path(lib)):
        path = os.path.abspath(lib)
        sys.path.append(str(Path(path).parent))
        try:
            global_vars = runpy.run_path(path, {})
        except Exception as error:
            raise AppFail(str(error))

        sys.argv[:] = [path, *argv]

        if name:
            # User has given a name, use that
            try:
                app = global_vars[name]
            except KeyError:
                raise AppFail(f"App {name!r} not found in {lib!r}")
        else:
            # User has not given a name
            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
                    )

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Verify the exact global name in the target file and use it after the colon: `textual run foo.py:app` where `app = MyApp()` exists at module level in foo.py
  2. Add a module-level assignment `app = MyApp()` to the file
  3. If you only have a class, either instantiate it at module level or pass the class-name variable that exists as a global
  4. Omit the name entirely (just `foo.py`) so Textual auto-discovers a global `app` or a unique App subclass/instance

Example fix

# before
# foo.py
class MyApp(App): ...
if __name__ == "__main__":
    MyApp().run()
# CLI: textual run foo.py:app  -> AppFail

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

Strategy: validation

Validate before calling

import runpy, inspect
from textual.app import App

def find_app_global(path: str, name: str) -> object | None:
    g = runpy.run_path(path)
    return g.get(name)

Type guard

def is_app(obj: object) -> TypeGuard[App]:
    return isinstance(obj, App) or (inspect.isclass(obj) and issubclass(obj, App))

Try / catch

from textual.app import App
try:
    app = import_app("foo.py:myapp")
except AppFail as e:
    print(f"Bad app reference: {e}")  # prompt user / fix path:name

Prevention

When it happens

Trigger: Calling textual's take_svg_screenshot or `textual run foo.py:myapp` where foo.py has no module-level variable named myapp; the app is instantiated inside `if __name__ == "__main__":` so no global name exists; the name is misspelled or uses different casing than the variable in the file.

Common situations: Apps created from templates that define `class MyApp(App)` but never assign `app = MyApp()` at module level; renaming the app variable in the file but not in the CLI argument; passing a class name when the file only has an instance (or vice versa); running the screenshot command from a docs/snippet file where the app is defined inside a function.

Related errors


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