Skip to Content
영화 리뷰 미션사라지는 원본 에러

사라지는 원본 에러

카테고리: error-handling · 이 패턴은 8기 PR 26건 중 17건에서 관찰됩니다.

catch 블록에서 원본 에러를 버리고 고정 문자열로 치환한다.

catch에서 잡은 원본 Error 객체를 그대로 버리고 동일한 안내 문자열만 다시 던지거나 표시하는 패턴입니다. 타임아웃, 네트워크 오류, HTTP 4xx/5xx 응답, 파싱 실패가 모두 한 종류의 에러로 평탄화되기 때문에 호출자는 원인을 구분할 수 없고 디버깅 단서도 함께 사라집니다.

문제 코드

다음은 실제 8기 크루 PR에서 추출한 코드입니다. 작성자는 익명 처리하고 원본 PR 링크만 남깁니다.

사례 1

} catch (error) { const newError = new Error(); newError.name = "API 요청중 에러가 발생했습니다." newError.message = `${error instanceof Error ? (error.message ?? "not found error message") : "not found error"} (${endpoint})` throw newError }

타임아웃, 네트워크, HTTP 응답 오류가 모두 동일한 Error 한 종류로 평탄화되어 호출자가 원인을 구분할 수 없습니다. 원본: PR #265  · src/utils.ts

사례 2

export async function getPopularMovies(page) { try { return await fetchApi(POPULAR_PATH, page); } catch (error) { throw new Error("영화 데이터를 불러오는 중 오류가 발생했습니다."); } }

원본 error 인자를 사용하지 않고 동일 문구로 새 Error를 만들기 때문에 status code와 message가 모두 사라집니다. 원본: PR #275  · src/features/movieModel.ts

사례 3

} catch (error) { if (error instanceof Error && error.name === "AbortError") { throw new Error(TIMEOUT_ERROR_MESSAGE); } throw error; }

AbortError를 새 Error로 감쌀 때 cause 옵션을 쓰지 않아 원본 스택과 메시지가 끊깁니다. 원본: PR #287  · src/API/api.ts

스스로 진단해보기

해설을 펼치기 전에 다음 질문에 답한다.

  1. 이 catch 블록에서 사라지는 정보가 무엇인지 한 줄로 적는다.
  2. 사용자에게 보여 줄 메시지와 개발자가 콘솔에서 확인할 정보를 같은 데이터로 합쳐도 되는지 판단한다.
  3. 이 함수의 호출자가 네트워크 오류와 4xx 응답을 구분해서 처리해야 할 상황을 한 가지 떠올린다.

해설

해설 보기

catch에서 잡은 error는 원인을 식별할 수 있는 거의 모든 정보를 담고 있는 객체입니다. 여기에는 원본 메시지, 스택 트레이스, 발생 위치, 그리고 fetch 실패라면 TypeError·AbortError 같은 구체적인 타입 정보가 포함됩니다. 고정 문자열로 새 Error를 만들어 다시 던지는 순간 이 정보들은 모두 버려지고, 호출자는 “무언가 잘못되었다”라는 사실 외에는 아무것도 알 수 없게 됩니다.

이 패턴은 세 가지 층에서 문제를 일으킵니다. 첫째, 디버깅 비용이 올라갑니다. 프로덕션에서 에러 리포트를 받아도 스택 트레이스가 throw new Error(...)가 위치한 줄에서 끊겨 있어 원인을 추적할 수 없습니다. 둘째, 호출자의 분기 처리가 불가능해집니다. 네트워크 단절과 404 응답은 사용자에게 다르게 안내해야 하지만, 문자열 하나로 좁혀지면 구분할 근거가 사라집니다. 셋째, 재시도 정책을 세울 수 없습니다. 일시적 네트워크 오류만 재시도해야 하는 상황에서 모든 에러가 동일하게 보이면 무차별 재시도나 무차별 포기 중 하나를 선택할 수밖에 없습니다.

해결의 핵심 개념은 “정보 보존”입니다. ES2022부터 Error 생성자의 cause 옵션을 사용하면 원본 에러를 체인으로 연결할 수 있습니다. 또는 커스텀 에러 클래스 를 만들어 status code와 원인 타입을 구조화된 필드로 남기는 방법도 있습니다. 어느 쪽이든 “상위 계층에 try...catch로 맥락을 덧붙이되 원본은 버리지 않는다”는 원칙은 동일합니다.

개선 방향

Before

} catch (error) { throw new Error("영화 데이터를 불러오는 중 오류가 발생했습니다."); }

After

} catch (error) { throw new Error(`영화 데이터를 불러오는 중 오류가 발생했습니다. (${endpoint})`, { cause: error, }); }

핵심 변화는 Error 생성자의 두 번째 인자 { cause }로 원본 에러를 체인에 남겼다는 점입니다. 사용자에게 보여 줄 메시지는 그대로 유지하면서도 개발자 도구와 로그 수집기에서는 원본 스택과 타입을 그대로 추적할 수 있습니다.

더 알아볼 개념

Last updated on