Application Servers & Java

java.lang.IllegalStateException: Unable to send an error after the response has been committed

midworker 2025. 5. 19. 22:33
반응형

웹 애플리케이션에서 예외 상황 발생 시, 다음과 같은 오류 로그를 접한 적이 있을 수 있습니다.


에러 메시지

java.lang.IllegalStateException: Unable to send an error after the response has been committed

원인 분석

이 오류는 HTTP 응답(Response)이 이미 클라이언트에 전송(commit)된 이후,
서버 쪽에서 다시 response.sendError() 또는 response.setStatus() 등을 호출하려고 할 때 발생합니다.

즉, 응답 헤더가 이미 전송된 상태에서는 상태 코드나 에러 페이지 전환이 불가능하기 때문에 발생하는 예외입니다.

언제 발생할까?

  • JSP에서 이미 일부 HTML이 브라우저로 전송된 후 예외 발생
  • 필터나 인터셉터에서 에러 응답을 시도했지만 이미 응답이 커밋된 경우
  • 컨트롤러나 핸들러에서 response.sendError() 호출이 너무 늦었을 때

🛠️ 해결 방법

1. response.isCommitted() 체크

에러 응답을 시도하기 전에 응답이 이미 커밋되었는지 확인하는 방어 코드를 추가합니다.

if (!response.isCommitted()) {
    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "처리 중 오류 발생");
} else {
    log.warn("응답이 이미 커밋되어 에러 전송 불가");
}

2. 예외는 가능한 빠르게 처리

  • JSP 또는 HTML 일부라도 출력되기 전에 예외를 처리해야 합니다.
  • 필터나 인터셉터 레벨에서 빠르게 캐치하거나, 예외 전용 핸들러를 도입합니다.

3. @ControllerAdvice 또는 @ExceptionHandler 사용

Spring MVC를 사용하는 경우, 글로벌 예외 처리기를 등록해 표준적인 방식으로 에러 처리가 가능합니다.

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handle(Exception ex) {
        return ResponseEntity.status(500).body("서버 오류가 발생했습니다.");
    }
}

4. Redirect 방식으로 처리 회피

이미 일부 응답이 전송된 이후라면 sendRedirect() 대신 로깅만 남기고 화면 처리 없이 흐름을 종료할 수도 있습니다.


결론

이 에러는 응답 흐름을 제어하는 데 있어 타이밍이 매우 중요하다는 점을 알려줍니다.
"응답이 커밋된 이후에는 더 이상 상태를 변경할 수 없다"는 HTTP의 특성을 고려하여,
예외 처리를 조기에 수행하거나 응답 커밋 여부를 먼저 확인하는 방식으로 안정성을 높일 수 있습니다.


반응형