기술 · 실용 가이드
Uvicorn이 모듈을 가져오지 못할 때: 앱 문자열·검색 경로·내부 traceback 증명
시작 오류를 세 가지로 나눕니다. Python이 모듈을 찾는지, 지정한 속성이 있는지, 가져오는 동안 다른 예외가 발생하는지 확인합니다.

“Error loading ASGI app. Could not import module”은 하나의 해결책을 뜻하지 않습니다. Uvicorn은 app.main:app 같은 APP 대상을 해석하고, Python은 app.main을 검색하며, 모듈 실행 중 다른 예외가 날 수도 있습니다.
수정 전에 실제 명령, 작업 디렉터리, 인터프리터와 첫 전체 traceback을 보존합니다.
1. 실패 명령과 환경을 고정
pwd(또는 Get-Location), python -c "import sys; print(sys.executable)", python -m uvicorn --version을 기록합니다. 서비스 관리자나 컨테이너라면 실제 cwd와 명령을 확인합니다.
python -m uvicorn은 방금 확인한 Python을 사용합니다. uvicorn 자체를 가져오지 못하면 앱 경로가 아니라 환경부터 고칩니다.
2. 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를 검색하고 --app-dir은 경로를 추가합니다. 프로젝트 루트의 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 형식을 사용합니다. 다른 파일이 나오면 가림 모듈을 제거합니다.
6. 패키지 import와 배포 환경 일치
FastAPI 다중 파일 예시는 app.main:app 같은 패키지 진입점을 씁니다. main.py를 느슨한 스크립트로 실행할 때와 패키지로 가져올 때 import 규칙이 다릅니다.
실제 서비스와 동일한 cwd, Python, 환경 변수와 마운트에서 재현합니다. 대화형 셸에서 cd한 뒤에만 성공하면 아직 배포 수정이 아닙니다.
7. 관찰 가능한 성공 조건으로 종료
먼저 reload와 여러 worker를 끄고 한 프로세스로 traceback을 하나만 남깁니다. 올바른 파일과 속성, 시작 완료, 알려진 경로 응답을 확인합니다.
직접 import가 실패하면 Uvicorn 옵션 변경을 멈춥니다. 터미널만 성공하면 서비스 관리자의 cwd, Python, 환경과 마운트를 비교합니다.
