"""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)})