Skip to content

에러 메시지로 진단하기

빨간 줄의 거대한 양의 에러 메세지를 보면 우리는 순간 당황해서 에러 메시지를 통째로 복사해 검색창에 붙여넣곤 해요. 하지만 에러 메시지는 의외로 친절하게 오류 원인을 알려 주고 있어요. 한 단어씩, 한 문장씩 차근차근 해석하면 문제 발생 지점을 짐작할 수 있는 중요한 단서를 얻을 수 있어요.

에러 메세지는 문제의 범위를 빠르게 좁힐 수 있는 가장 강력한 힌트예요. 에러를 진단할 때는 단순히 메시지를 보는 것에 그치지 않고, 해당 메시지가 무엇을 의미하는지, 어떤 맥락에서 발생했는지, 어떤 가능성부터 확인하면 좋은지 차근히 살펴보는 게 중요해요. 이 페이지에서는 각 에러 메시지 종류에 대한 이해를 높일 수 있는 설명과, 무엇을 확인해야 하는지 알려드려요.

문법 오류일 때 (SyntaxError)

코드에 문법적인 문제가 있을 때는 보통 "SyntaxError: ~"로 시작하는 에러 메시지가 출력돼요. 이 메시지는 자바스크립트 엔진이 코드를 실행하기도 전에 문법을 해석하다가 실패했음을 알려주는 신호예요.

unexpected '}'} 괄호에 문제가 있다는 뜻이에요. 괄호가 닫히지 않았거나, 불필요한 괄호가 추가되었을때, 혹은 exportreturn 같은 예약어를 잘못 썼을 때 아래와 같은 메시지를 볼 수 있어요.

tsx
function run() {
  const name = 'Hello'
  if (true) {
    console.log(name)
  }
}}

Unexpected '<' 에러 메세지는 보통 잘못된 URL로 인해 HTML 응답을 JSON으로 파싱하려는 시도에서 발생해요. 에러 메세지의 'html...is not valid JSON' 이라는 문구에서 JSON.parse의 인자로 잘못된 타입의 데이터가 들어갔음을 추측해볼 수 있어요.

js
JSON.parse("<!DOCTYPE html><html><body>oops</body></html>");

작은따옴표와 큰따옴표의 매칭이 잘못된 경우에도 "기대하지 않은 '(' 가 보인다" 라는 에러 메세지가 보여요.

tsx
JSON.parse('{ foo: "bar" }");

확인할 것

  • 문법에 맞게 작성되었는지 확인해요.
  • 사용자가 코드를 작성하는 동안 IDE가 구문 오류를 실시간으로 감지해 강조 표시를 해줘요. 그래서 코드를 작성하면서 문법 오류를 바로 파악하고 고칠 수 있어요.

타입 오류일 때 (TypeError)

값의 타입이 예상과 다를 때는 "TypeError: ~"로 시작하는 에러 메시지가 출력돼요. 이 에러는 주로 정의되지 않았거나, 잘못된 값에 접근하거나, 함수가 아닌 값을 함수처럼 호출했을 때 발생해요.

예를 들어 객체가 null이나 undefined인 상태에서 속성에 접근하려고 하면 이런 메시지를 볼 수 있어요.

tsx
const user = null;
console.log(user.name);

함수가 아닌 객체를 호출하면 다음과 같은 에러 메세지가 나요.

tsx
const num = 42;
num();

async 함수 안에서 비동기 작업을 실행할 때 await를 빠뜨리면 의도하지 않은 동작이나 Promise 타입 관련 오류가 발생할 수 있어요. 예를 들어, 함수가 Promise를 반환하는데 이를 await하지 않고 그대로 사용하면 타입스크립트는 Promise<T>T를 혼동해서 에러를 발생시켜요.

tsx
async function getMessage() {
  return "Hello, world!";
}

function printMessage(msg) {
  console.log(msg);
}

function main() {
  const message = getMessage();
  printMessage(message);
}
main();

확인할 것

  • 객체가 실제로 존재하는지 확인해요.
  • API 응답 데이터 구조가 맞는지 확인해요.
  • typeof, Array.isArray() 등으로 미리 검사했는지 확인해요.
  • await 누락 여부를 확인해요.

참조 오류일 때 (ReferenceError)

ReferenceError정의되지 않은 식별자(변수나 함수 이름 등)를 사용하려고 할 때 발생해요. 즉, 자바스크립트 엔진이 해당 이름을 찾을 수 없을 때 나타나는 에러예요.

예를 들어, 아래처럼 변수를 선언하지 않고 사용하면 에러가 발생해요.

tsx
console.log(userName);
let userName = "Alice";

확인할 것

  • 변수가 선언되었는지 확인해요.
  • 선언보다 먼저 접근한 건 아닌지 확인해요.
  • 외부 스코프 참조가 의도한 것인지 확인해요.

리소스 로딩 오류일 때

외부 자원을 가져오는 요청이 네트워크 단계에서 실패하면 브라우저는 fetch에서 TypeError를 던져요. 브라우저에 따라 "TypeError: Load failed" 또는 "TypeError: Failed to fetch"로 나타나요. 이 에러는 HTTP 4xx, 5xx 같은 응답 에러와 다르게 네트워크 자체가 실패했거나 보안 정책으로 차단됐을 때 발생해요. 이 경우엔 reject되어 바로 catch문으로 넘어가요.

tsx
fetch("https://api.otherdomain.com/data")
  .then((res) => res.json())
  .catch((err) => {
    console.error(err.message);
  });

참고로, HTTP 4xx, 5xx 같은 응답 에러가 발생했을 때는 reject하여 catch로 넘기지 않고 res.okfalse인 응답을 돌려줘요.

ts
fetch("/api/data")
  .then(async (res) => {
    if (!res.ok) {
      const text = await res.text();
      throw new Error(
        `서버 오류: HTTP ${res.status} ${res.statusText} ${text}`
      );
    }
    return res.json();
  })
  .catch((err) => console.error(err));

확인할 것

  • 콘솔에 TypeError: Load failedFailed to fetch가 보이면 네트워크, CORS, 인증서, CSP(Content Security Policy), 확장 프로그램 차단 가능성을 먼저 의심해요.

모듈 import 오류일 때

모듈을 import 하는 과정에서도 문법 오류(SyntaxError)가 발생할 수 있어요. 특히 ES 모듈(ESM)과 CommonJS(CJS) 방식이 혼합된 환경에서는 설정이 서로 충돌해서 문법 오류처럼 보이는 에러가 나타날 수 있어요. 이때 모듈 관련 에러 메시지를 보면 단순 문법 문제가 아니라 모듈 시스템 설정에 문제가 있을 가능성을 유추할 수 있어요.

예를 들어, .js 파일에 import 구문을 사용하게 되면 아래와 같은 에러 메시지가 나타나요. Node.js는 기본적으로 .js 파일을 CommonJS로 해석하기 때문에, import를 사용할 수 없고 require()를 써야 해요.

js
// example.js
import fs from "fs";

fs.readFile("example.txt", "utf8", (err, data) => {
  if (err) throw err;
  console.log(data);
});

확인할 것

  • 프로젝트의 모듈 시스템 설정이 올바른지 확인해요.
    • ESM 사용 시: package.json"type": "module" 설정을 확인해요.
    • CommonJS 사용 시: "type" 필드를 생략하거나, "type": "commonjs"로 명시해도 돼요.
  • .mjs, .cjs, .js 확장자가 적절히 사용됐는지 확인해요.
  • 잘못된 번들 경로로 esm 전용 모듈을 가져오지 않았는지 확인해요.

📚 더 알아보기