テクノロジー · 実用ガイド
Uvicorn がモジュールを import できない?APP・検索パス・内部 traceback を順に証明
起動エラーを三つに分けます。Python がモジュールを見つけるか、属性が存在するか、import 中に別の例外が起きるかを確認します。

「Error loading ASGI app. Could not import module」は一つの修正を意味しません。Uvicorn は app.main:app のような APP を解析し、Python が app.main を検索し、さらに import 実行中に別の例外が起こることがあります。
編集前にコマンド、作業ディレクトリ、インタープリター、最初の完全な traceback を保存します。
1. 失敗したコマンドと環境を固定
pwd(PowerShell は Get-Location)、python -c "import sys; print(sys.executable)"、python -m uvicorn --version を記録します。サービスやコンテナでは実際の作業ディレクトリとコマンドを確認します。
python -m uvicorn は確認した Python を使います。uvicorn 自体を import できないなら、アプリのパスではなく環境を先に直します。
2. APP を module:attribute として解析
app.main:app では module が app.main、attribute が app です。.py、スラッシュ、推測したルート名を加えません。
create_app のような callable なら対象名と --factory を意図的に指定します。属性不足とモジュール不足は別の障害です。
3. Python がモジュールを見つけるか証明
同じ場所で python -c "import importlib.util; print(importlib.util.find_spec('app.main'))" を実行します。None は現在の検索パスで見つからないことを示します。
Python は sys.path を検索し、--app-dir は検索ディレクトリを追加します。プロジェクト root から app.main:app、app 内から main:app、または固定したサービス cwd と絶対 --app-dir のどれか一つにします。
4. 直接 import して本当の traceback を出す
find_spec が成功したら python -c "import app.main" を実行します。依存関係、構文、設定読み込み、循環 import を指すなら、モジュールは見つかっており実行中に失敗しています。
ディレクトリ追加やファイル名変更では、欠けた依存関係や循環 import は直りません。
5. サーバーを起動せず属性を確認
python -c "import app.main as m; print(m.__file__); print(hasattr(m, 'app')); print(type(getattr(m, 'app', None)))" を使います。__file__ は同名モジュール、hasattr は属性不足を見つけます。
対象が application なら app.main:application、factory なら factory 形式を使います。違うファイルが表示されたら shadowing を解消します。
6. パッケージ import と配置を一致
FastAPI の複数ファイル例は app.main:app のような package entrypoint を使います。main.py を単独 script として動かす場合と package として import する場合では import 規則が変わります。
本番サービスと同じ cwd、Python、環境変数、マウントで再現します。対話 shell で cd した時だけ動く状態は配置修正ではありません。
7. 観測できる成功条件で終了
まず reload と複数 worker を切り、1プロセスで traceback を一つにします。正しいファイルと属性、startup 完了、既知 route の応答を確認します。
直接 import が失敗する間は Uvicorn の flag を変えません。terminal だけ成功するなら service manager の cwd、Python、環境、マウントを比較します。
