에러 메시지로 진단하기

빨간 줄의 거대한 양의 에러 메세지를 보면 우리는 순간 당황해서 에러 메시지를 통째로 복사해 검색창에 붙여넣곤 해요. 하지만 에러 메시지는 의외로 친절하게 오류 원인을 알려 주고 있어요. 한 단어씩, 한 문장씩 차근차근 해석하면 문제 발생 지점을 짐작할 수 있는 중요한 단서를 얻을 수 있어요.
에러 메세지는 문제의 범위를 빠르게 좁힐 수 있는 가장 강력한 힌트예요. 에러를 진단할 때는 단순히 메시지를 보는 것에 그치지 않고, 해당 메시지가 무엇을 의미하는지, 어떤 맥락에서 발생했는지, 어떤 가능성부터 확인하면 좋은지 차근히 살펴보는 게 중요해요. 이 페이지에서는 각 에러 메시지 종류에 대한 이해를 높일 수 있는 설명과, 무엇을 확인해야 하는지 알려드려요.
문법 오류일 때 (SyntaxError)
코드에 문법적인 문제가 있을 때는 보통 "SyntaxError: ~"로 시작하는 에러 메시지가 출력돼요. 이 메시지는 자바스크립트 엔진이 코드를 실행하기도 전에 문법을 해석하다가 실패했음을 알려주는 신호예요.

unexpected '}'는 } 괄호에 문제가 있다는 뜻이에요. 괄호가 닫히지 않았거나, 불필요한 괄호가 추가되었을때, 혹은 export나 return 같은 예약어를 잘못 썼을 때 아래와 같은 메시지를 볼 수 있어요.
function run() {
const name = 'Hello'
if (true) {
console.log(name)
}
}}Unexpected '<' 에러 메세지는 보통 잘못된 URL로 인해 HTML 응답을 JSON으로 파싱하려는 시도에서 발생해요. 에러 메세지의 'html...is not valid JSON' 이라는 문구에서 JSON.parse의 인자로 잘못된 타입의 데이터가 들어갔음을 추측해볼 수 있어요.

JSON.parse("<!DOCTYPE html><html><body>oops</body></html>");작은따옴표와 큰따옴표의 매칭이 잘못된 경우에도 "기대하지 않은 '(' 가 보인다" 라는 에러 메세지가 보여요.

JSON.parse('{ foo: "bar" }");확인할 것
- 문법에 맞게 작성되었는지 확인해요.
- 사용자가 코드를 작성하는 동안 IDE가 구문 오류를 실시간으로 감지해 강조 표시를 해줘요. 그래서 코드를 작성하면서 문법 오류를 바로 파악하고 고칠 수 있어요.
타입 오류일 때 (TypeError)
값의 타입이 예상과 다를 때는 "TypeError: ~"로 시작하는 에러 메시지가 출력돼요. 이 에러는 주로 정의되지 않았거나, 잘못된 값에 접근하거나, 함수가 아닌 값을 함수처럼 호출했을 때 발생해요.

예를 들어 객체가 null이나 undefined인 상태에서 속성에 접근하려고 하면 이런 메시지를 볼 수 있어요.
const user = null;
console.log(user.name);함수가 아닌 객체를 호출하면 다음과 같은 에러 메세지가 나요.

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


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

예를 들어, 아래처럼 변수를 선언하지 않고 사용하면 에러가 발생해요.
console.log(userName);
let userName = "Alice";확인할 것
- 변수가 선언되었는지 확인해요.
- 선언보다 먼저 접근한 건 아닌지 확인해요.
- 외부 스코프 참조가 의도한 것인지 확인해요.
리소스 로딩 오류일 때
외부 자원을 가져오는 요청이 네트워크 단계에서 실패하면 브라우저는 fetch에서 TypeError를 던져요. 브라우저에 따라 "TypeError: Load failed" 또는 "TypeError: Failed to fetch"로 나타나요. 이 에러는 HTTP 4xx, 5xx 같은 응답 에러와 다르게 네트워크 자체가 실패했거나 보안 정책으로 차단됐을 때 발생해요. 이 경우엔 reject되어 바로 catch문으로 넘어가요.

fetch("https://api.otherdomain.com/data")
.then((res) => res.json())
.catch((err) => {
console.error(err.message);
});참고로, HTTP 4xx, 5xx 같은 응답 에러가 발생했을 때는 reject하여 catch로 넘기지 않고 res.ok가 false인 응답을 돌려줘요.
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 failed나Failed to fetch가 보이면 네트워크, CORS, 인증서, CSP(Content Security Policy), 확장 프로그램 차단 가능성을 먼저 의심해요.
모듈 import 오류일 때
모듈을 import 하는 과정에서도 문법 오류(SyntaxError)가 발생할 수 있어요. 특히 ES 모듈(ESM)과 CommonJS(CJS) 방식이 혼합된 환경에서는 설정이 서로 충돌해서 문법 오류처럼 보이는 에러가 나타날 수 있어요. 이때 모듈 관련 에러 메시지를 보면 단순 문법 문제가 아니라 모듈 시스템 설정에 문제가 있을 가능성을 유추할 수 있어요.

예를 들어, .js 파일에 import 구문을 사용하게 되면 아래와 같은 에러 메시지가 나타나요. Node.js는 기본적으로 .js 파일을 CommonJS로 해석하기 때문에, import를 사용할 수 없고 require()를 써야 해요.
// 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"로 명시해도 돼요.
- ESM 사용 시:
.mjs,.cjs,.js확장자가 적절히 사용됐는지 확인해요.- 잘못된 번들 경로로
esm전용 모듈을 가져오지 않았는지 확인해요.