科技 · 實用指南
Uvicorn 無法匯入模組?先驗證應用字串、搜尋路徑與內部回溯
把啟動錯誤拆成三個測試:Python 能否找到模組、指定屬性是否存在,以及匯入模組時是否觸發另一個例外。

「Error loading ASGI app. Could not import module」並不對應唯一修復。Uvicorn 先解析 app.main:app 之類的 APP 目標,Python 再搜尋 app.main,而匯入時還可能執行並拋出另一個例外。
編輯檔案前,保留原始指令、工作目錄、直譯器與第一份完整回溯;流程只修改真正失敗的那一層。
1. 固定失敗指令與環境
記錄原指令、目前目錄與直譯器:pwd(PowerShell 用 Get-Location)、python -c "import sys; print(sys.executable)"、python -m uvicorn --version。服務管理器或容器則記錄其工作目錄與指令。
python -m uvicorn 會使用剛核對的直譯器;若連 uvicorn 都不能匯入,先修復環境或呼叫方式。
2. 依 module:attribute 逐字解析 APP
官方格式是 <module>:<attribute>。app.main:app 中模組是 app.main、屬性是 app;不要加入 .py、斜線或任意專案根目錄名稱。
若物件由 create_app 等 callable 建立,應指向該物件並明確使用 --factory。屬性缺失與模組找不到是不同故障。
3. 證明 Python 能找到模組
在相同目錄與直譯器執行 python -c "import importlib.util; print(importlib.util.find_spec('app.main'))"。None 代表目前搜尋路徑無法定位模組,不代表檔案不存在。
Python 會遍歷 sys.path;Uvicorn 的 --app-dir 會加入搜尋目錄。固定一種契約:從專案根執行 app.main:app、從 app 目錄執行 main:app,或固定服務目錄並傳絕對 --app-dir。
4. 直接匯入以顯示真正回溯
若 find_spec 可定位,執行 python -c "import app.main"。回溯若指向依賴、語法、設定讀取或循環匯入,就表示模組已找到但匯入體執行失敗。
通用 Uvicorn 訊息可能掩蓋內部例外;增加目錄或改名不能修復缺少依賴與循環匯入。
5. 不啟動伺服器也能驗證屬性
匯入成功後執行 python -c "import app.main as m; print(m.__file__); print(hasattr(m, 'app')); print(type(getattr(m, 'app', None)))"。檔案路徑抓同名遮蔽,hasattr 區分屬性問題。
物件若叫 application 就用 app.main:application;工廠則用對應形式。若檔案不是專案檔案,先移除遮蔽模組。
6. 維持套件匯入與部署一致
FastAPI 多檔案範例使用 app.main:app 類型的套件入口。把 main.py 當鬆散腳本與把 app.main 當套件匯入,允許的匯入方式不同。
在真實服務的工作目錄、直譯器、環境變數與掛載中重現最終指令;只有互動 shell 先 cd 才成功,尚不算部署修復。
7. 以可觀察結果作為退出條件
先停用 reload 與多 worker,以單一程序保留一份回溯。成功標準是模組檔案與屬性正確、啟動完成、已知路由能回應。
直接匯入仍失敗就停止調整 Uvicorn 旗標;終端通過但服務管理器失敗時,比較目錄、直譯器、環境與掛載。
