{"record":{"id":"7e04c02168e7b836","repo":"Textualize/textual","slug":"unable-to-find-app-in-lib-r-try-specifying-app","errorCode":null,"errorMessage":"Unable to find app in {lib!r}, try specifying app with \"foo.py:app\"","messagePattern":"Unable to find app in (.+?), try specifying app with \"foo\\.py:app\"","errorType":"exception","errorClass":"AppFail","httpStatus":null,"severity":"error","filePath":"src/textual/_import_app.py","lineNumber":97,"sourceCode":"            if \"app\" in global_vars:\n                # App exists, lets use that\n                try:\n                    app = global_vars[\"app\"]\n                except KeyError:\n                    raise AppFail(f\"App {name!r} not found in {lib!r}\")\n            else:\n                # Find an App class or instance that is *not* the base class\n                apps = [\n                    value\n                    for value in global_vars.values()\n                    if (\n                        isinstance(value, App)\n                        or (inspect.isclass(value) and issubclass(value, App))\n                        and value is not App\n                    )\n                ]\n                if not apps:\n                    raise AppFail(\n                        f'Unable to find app in {lib!r}, try specifying app with \"foo.py:app\"'\n                    )\n                if len(apps) > 1:\n                    raise AppFail(\n                        f'Multiple apps found {lib!r}, try specifying app with \"foo.py:app\"'\n                    )\n                app = apps[0]\n        app._BASE_PATH = path\n\n    else:\n        # Assuming the user wants to import the file\n        sys.path.append(\"\")\n        try:\n            module = importlib.import_module(lib)\n        except ImportError as error:\n            raise AppFail(str(error))\n\n        find_app = name or \"app\"","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/_import_app.py#L79-L115","documentation":"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.","triggerScenarios":"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.","commonSituations":"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__.","solutions":["Specify the app explicitly with path:name syntax: `textual run foo.py:MyApp`","Move the App subclass or instance to module level in the target file","Point the command at the file that actually defines the app, not a helper module","Import the app into the entry file so it becomes a global there"],"exampleFix":"# before\n# myapp.py\ndef make_app():\n    class MyApp(App): ...\n    return MyApp()\n# CLI: textual run myapp.py  -> AppFail\n\n# after\n# myapp.py\nclass MyApp(App): ...\napp = MyApp()\n# CLI: textual run myapp.py:app","handlingStrategy":"validation","validationCode":"import runpy, inspect\nfrom textual.app import App\n\ndef discover_apps(path: str) -> list:\n    g = runpy.run_path(path)\n    return [v for v in g.values()\n            if isinstance(v, App) or (inspect.isclass(v) and issubclass(v, App) and v is not App)]\n\n# assert len(discover_apps(\"foo.py\")) >= 1 before invoking textual","typeGuard":null,"tryCatchPattern":"try:\n    app = import_app(\"foo.py\")\nexcept AppFail as e:\n    # fall back to explicit naming\n    app = import_app(\"foo.py:MyApp\")","preventionTips":["Give every entry file exactly one module-level App subclass or instance","In tests, assert discover_apps(entry) is non-empty","Avoid defining apps only inside functions or __main__ guards"],"tags":["textual","import","app-discovery","cli"],"backgroundTag":"entrypoint-not-found","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}