결함 1 — 업로드 세션이 인증 세션을 가리고 있었다
- finalize_project_upload가 Depends(verify_session)로 받은 session을 같은 이름으로
덮어써, str(session["role"])이 업로드 세션 행에서 role을 찾다 KeyError를 냈다.
KeyError는 LookupError 하위라 404 {"message": "'role'"}로 나가고 로그도 안 남았다.
- 업로드 세션 변수를 upload_session으로 분리(청크 업로드·finalize·상태 조회 3곳).
- B03_FileInput_Router_Errors.lookup_error_response() 신설: 조회 실패만 404,
KeyError·IndexError는 500 + 예외 로그. 두 라우터의 LookupError 처리 13곳에 적용.
batch 단위 엔드포인트에는 batch_id를, 프로젝트 단위에는 project_id를 로그 필드로 준다.
결함 4 — fail_stage가 예외 문자열을 그대로 넣어 UPDATE가 죽었다
- project_workflow_stages.message는 varchar(255)인데 PermissionError 메시지는 300자를
넘겨 DataError로 실패했고, 단계가 FAILED로 못 가 화면이 영영 "분석 중"이었다.
- 200자로 자르고 말줄임표를 붙인다. 원문은 호출부 로그에 남는다.
검증(실서버, 신규 프로젝트 f45243b3에 표본 5개 직접 청크 업로드):
finalize 성공 11건 / "'role'" 오류 0건, 마지막 파일 complete_upload=true도 성공.
이어서 WF1 자동 분석이 시작됨(stage 0 COMPLETE, stage 1 IN_PROGRESS) — 종전에는
예외가 스케줄링 앞에서 터져 자동 분석이 아예 걸리지 않았다.
ruff format·check 통과.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
32 lines
1.3 KiB
Python
32 lines
1.3 KiB
Python
"""B03 라우터 공통 오류 응답 — 조회 실패와 코드 버그를 갈라 준다.
|
|
|
|
`LookupError`를 통째로 404로 돌리면 `KeyError`·`IndexError` 같은 **코드 버그까지 404로
|
|
조용히 덮인다**. 실제로 업로드 finalize에서 `KeyError('role')`이 404 `{"message": "'role'"}`
|
|
로 나가 로그도 안 남고, 마지막 파일 업로드가 매번 실패로 보이던 사고가 있었다
|
|
(2026-08-08 E2E 점검). 조회 실패(레코드 없음)만 404로 두고 버그는 500 + 로그로 보낸다.
|
|
"""
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from fastapi.responses import JSONResponse
|
|
|
|
|
|
def lookup_error_response(
|
|
exc: LookupError,
|
|
logger: logging.Logger,
|
|
*,
|
|
context: str,
|
|
fallback_message: str = "요청을 처리하지 못했습니다.",
|
|
**log_fields: Any,
|
|
) -> JSONResponse:
|
|
"""조회 실패면 404, 코드 버그(`KeyError`·`IndexError`)면 500 + 예외 로그."""
|
|
if isinstance(exc, (KeyError, IndexError)):
|
|
detail = " ".join(f"{key}=%s" for key in log_fields)
|
|
logger.exception(f"{context} 처리 중 내부 오류 {detail}".strip(), *log_fields.values())
|
|
return JSONResponse(
|
|
status_code=500,
|
|
content={"status": "error", "message": fallback_message},
|
|
)
|
|
return JSONResponse(status_code=404, content={"status": "error", "message": str(exc)})
|