Textualize/textual · error · AppFail
Unable to find {find_app!r} in {module!r}
Error message
Unable to find {find_app!r} in {module!r} What it means
Raised when Textual imports an app from an installed module (a dotted import path like `mylib.myapp`) and the attribute lookup for the requested name (or the default "app") fails with AttributeError. Unlike the file-based path, this branch uses importlib and getattr on the module object, so the name must be a real attribute of that package/module. It is wrapped in AppFail and typically surfaces from `textual run mylib.myapp:Something`.
Source
Thrown at src/textual/_import_app.py:119
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"
try:
app = getattr(module, find_app or "app")
except AttributeError:
raise AppFail(f"Unable to find {find_app!r} in {module!r}")
sys.argv[:] = [import_name, *argv]
if inspect.isclass(app) and issubclass(app, App):
app = app()
return cast(App, app)
View on GitHub (pinned to 06dbeef4bb)
Solutions
- Reference the exact submodule and attribute: `textual run mylib.app:app`
- Re-export the app in the package's __init__.py (e.g. `from mylib.app import app`
- Check for typos and the installed package version (pip show / pip install -e .)
- If you meant a file on disk, use the path form `./mylib/app.py:app` instead of the dotted module form
Example fix
# before # mylib/__init__.py is empty; app lives in mylib/main.py # CLI: textual run mylib:app -> AppFail # after # mylib/__init__.py from mylib.main import app # CLI: textual run mylib:app
Defensive patterns
Strategy: validation
Validate before calling
import importlib
def module_has(module_name: str, attr: str) -> bool:
try:
mod = importlib.import_module(module_name)
except ImportError:
return False
return hasattr(mod, attr)
# assert module_has("mylib", "app") before textual run mylib:app Type guard
def exposes_app(mod) -> TypeGuard[object]:
return hasattr(mod, "app") Try / catch
try:
app = import_app("mylib:app")
except AppFail as e:
print(f"Missing export: {e}"); raise Prevention
- Re-export the app in your package __init__.py
- Pin and verify the installed package version in CI
- Double-check dotted module vs file-path syntax
When it happens
Trigger: Running `textual run mylib:MyApp` where MyApp is not exported from mylib/__init__.py; using the default `app` name when the package exposes none; typo in the attribute or package path; the app lives in a submodule like mylib.app but you referenced mylib.
Common situations: Packages that don't re-export the app in __init__.py; renaming the public app variable without updating docs/CI commands; mixing up file paths and module paths (using dots where a path is needed); stale installed version of the package missing the symbol.
Related errors
- App {name!r} not found in {lib!r}
- Unable to find app in {lib!r}, try specifying app with "foo.
- Multiple apps found {lib!r}, try specifying app with "foo.py
- SyntaxAwareDocument unavailable - tree-sitter is not install
- Can't animate attribute {attribute!r} on {obj!r}; attribute
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/b4919d9cf6a2982b.
Report an issue: GitHub.