본문 바로가기
IT

Cannot read properties of undefined (reading 'x') — 원인·해결·예방

by 샤나엘 2026. 6. 29.
반응형

Cannot read properties of undefined (reading 'x') — 원인·해결·예방

자바스크립트를 쓰다 보면 콘솔에서 가장 자주 만나는 빨간 줄이 이것이다. "TypeError: Cannot read properties of undefined (reading 'x')". 해석하면 "undefined인 값에서 x라는 속성을 읽으려 했다"는 뜻이다. 분명 객체가 있을 줄 알았는데 그 자리가 undefined라, 그 안의 속성에 손을 뻗는 순간 터진다. API 응답이 아직 안 왔거나, 객체 경로에 오타가 있거나, 함수가 아무것도 반환하지 않았을 때 흔하다. 다행히 메시지가 친절하다. 괄호 안의 (reading 'x')가 "어느 속성에서 막혔는지"를 콕 집어 준다. 이 글은 이 에러의 의미, 원인, 그리고 옵셔널 체이닝을 비롯한 해결·예방을 정리한다.

Cannot read properties of undefined (reading 'x')

 

이 글의 구성

 

🔎에러 메시지의 의미
🧩자주 나오는 발생 원인 4가지
💻재현과 (reading 'x') 읽는 법
🛠해결 방법 — 옵셔널 체이닝 외
⚖️undefined vs null의 차이
💬자주 묻는 질문 5가지

🔎 에러 메시지의 의미

이 에러는 TypeError의 한 종류다. 자바스크립트에서 값이 undefined인데 그 값의 속성(property)에 접근하려 하면 발생한다. undefined는 "아무것도 없음"을 뜻하는데, 없는 것에서 무언가를 꺼내려 하니 엔진이 멈추고 에러를 던진다.

 

메시지를 한 조각씩 보면 명확하다. Cannot read properties of undefined는 "undefined의 속성을 읽을 수 없다"는 뜻이고, 뒤따르는 (reading 'x')는 "그중에서도 x라는 속성을 읽으려다 막혔다"는 구체적 단서다. 즉 코드 어딘가에서 무언가.x를 했는데, 그 무언가가 undefined였던 것이다. 참고로 예전 브라우저는 같은 상황을 "Cannot read property 'x' of undefined"라는 옛 문구로 보여줬는데, 의미는 동일하다.

핵심 — 점 왼쪽이 undefined였다

user.profile.name에서 이 에러가 났다면, name이 문제가 아니라 그 앞의 user.profile이 undefined였다는 뜻이다. (reading 'name')은 "name을 읽으려는 순간" 막혔다고 알려줄 뿐, 정작 비어 있던 건 점 바로 왼쪽 값이다. 그래서 디버깅은 "막힌 속성의 한 단계 왼쪽"을 들여다보는 데서 시작한다.


🧩 자주 나오는 발생 원인 4가지

원인 1 — 비동기 데이터가 아직 안 옴

가장 흔하다. API 응답이 도착하기 전에 화면이 먼저 그려지면서 data.user처럼 접근하는 경우다. 처음 렌더링 시점엔 data가 undefined라 속성 접근에서 터진다. React 같은 프레임워크에서 특히 잦다.

원인 2 — 객체 경로 오타·잘못된 중첩 접근

res.data.items인데 res.datas.items로 잘못 쓰거나, 한 단계를 빼먹은 경우다. 중간 경로가 undefined가 되면서 그다음 속성에서 에러가 난다. 깊은 중첩일수록 자주 생긴다.

원인 3 — 함수가 값을 반환하지 않음

return을 빠뜨린 함수는 undefined를 돌려준다. 그 결과를 받아 .property로 접근하면 에러다. find()가 일치 항목을 못 찾아 undefined를 반환했을 때도 마찬가지다.

원인 4 — 배열 빈 인덱스·구조 분해 실패

arr[5]가 없는데 arr[5].name을 읽거나, 구조 분해에서 없는 객체를 풀어 쓰는 경우다. 빈 배열의 첫 요소(arr[0])에 접근하는 실수도 흔하다.


💻 재현과 (reading 'x') 읽는 법

전형적인 재현 코드다. 중첩 객체에서 중간 경로가 비어 있을 때 터진다.

// user는 있지만 profile은 아직 없음
const user = { name: "김개발" };

// profile이 undefined → 그 안의 name 접근에서 터짐
console.log(user.profile.name);
// ✗ TypeError: Cannot read properties of undefined (reading 'name')

메시지 읽는 법이 핵심이다. (reading 'name')은 "name을 읽다 막혔다"는 뜻이고, 진짜 undefined였던 건 그 한 단계 왼쪽인 user.profile이다. 콘솔의 에러를 클릭하면 몇 번째 줄에서 났는지 스택 추적이 나오니, 그 줄에서 "막힌 속성의 왼쪽"을 확인하면 된다.

// ✓ 어디서 끊기는지 한 단계씩 찍어 확인
console.log(user);          // { name: "김개발" }
console.log(user.profile);  // undefined  ← 여기가 범인

🛠 해결 방법 — 옵셔널 체이닝 외

가장 깔끔한 현대적 해법은 옵셔널 체이닝(?.)이다. ?. 바로 앞 값이 undefined나 null이면 더 들어가지 않고 안전하게 undefined를 돌려준다. 주의할 점은 ?.가 "바로 앞 한 단계"만 보호한다는 것이다. a.b?.c에서 a가 undefined면 a.b를 먼저 평가하다 여전히 터진다. 그래서 깊은 체인은 위험한 단계마다 a?.b?.c처럼 붙여 줘야 한다.

// ✓ 옵셔널 체이닝 — profile이 없어도 안전
console.log(user.profile?.name);   // undefined (에러 X)

// ✓ 기본값까지 — 없으면 대체값
const name = user.profile?.name ?? "이름 없음";

// ✓ 배열·함수 호출에도
arr?.[0]?.name;
obj.method?.();

상황별로 손이 더 가는 가드도 함께 알아 두면 좋다. 어떤 자리에선 옵셔널 체이닝보다 명시적 분기·기본값이 더 읽기 쉽다.

상황별 방어 방법

 

01옵셔널 체이닝 ?. — 중첩 객체 접근의 기본기. 없으면 undefined로 단락.
02널 병합 ?? — undefined·null일 때만 대체값. (0·""은 그대로 살림)
03기본값 구조 분해 — const { profile = {} } = user 로 빈 객체 보장.
04로딩 가드 — 데이터 도착 전엔 일찍 return하거나 로딩 UI를 먼저 그린다.
05근본 점검 — 그 값이 왜 undefined인지(오타·미반환·타이밍)부터 고친다.

옵셔널 체이닝은 강력하지만 만능은 아니다. 에러를 막아 주는 것과 데이터가 실제로 있는 건 다른 문제다. 화면에 계속 "이름 없음"만 뜬다면, ?.로 에러는 가렸어도 정작 profile이 비어 있는 근본 원인은 그대로다. 그래서 방어와 함께 "왜 비었는지"를 늘 같이 본다.


⚖️ undefined vs null의 차이

이 에러의 사촌으로 "Cannot read properties of null (reading 'x')"이 있다. 메시지가 거의 같지만 비어 있던 값의 종류가 다르다. 둘을 구분하면 원인 추적이 빨라진다.

의미 주로 어디서
undefined 값이 아직 할당되지 않음 없는 속성·미반환 함수·비동기 전
null "비어 있음"을 일부러 넣음 DOM 못 찾은 querySelector, 명시적 초기화

쉽게 말해 undefined는 "아직 안 채워짐", null은 "비었다고 의도적으로 표시함"이다. 예를 들어 document.querySelector가 요소를 못 찾으면 null을 반환하므로, 그 결과에 .value를 바로 접근하면 "of null" 쪽 에러가 난다. 다행히 옵셔널 체이닝(?.)과 널 병합(??)은 undefined와 null을 똑같이 안전하게 처리하므로, 해결 도구는 양쪽에 공통으로 쓸 수 있다.

(reading 'x')는 막힌 속성을 알려줄 뿐, 비어 있던 건 점 왼쪽이다. 옵셔널 체이닝으로 막되, 왜 비었는지는 따로 고쳐라.

 

— 에러를 가리는 것과 데이터가 있는 건 다르다


💬 자주 묻는 질문 5가지

Q1(reading 'name')이면 name이 문제인가요?

아닙니다. name을 읽으려는 순간 막혔다는 뜻이고, 정작 undefined였던 건 그 앞(점 왼쪽) 값입니다. user.profile.name에서 이 에러가 나면 profile이 비어 있던 것이죠. 디버깅은 막힌 속성의 한 단계 왼쪽부터 확인하세요.

Q2옵셔널 체이닝만 붙이면 끝인가요?

에러는 막아 주지만 근본 해결은 아닙니다. ?.는 값이 없으면 undefined로 단락할 뿐, 그 값이 왜 비었는지는 그대로입니다. 화면에 데이터가 안 뜬다면 오타·미반환·비동기 타이밍 같은 진짜 원인을 따로 고쳐야 합니다.

Q3API 데이터에서 자꾸 나요.

응답이 도착하기 전 첫 렌더링에서 객체가 undefined라 생기는 전형적 경우입니다. 데이터 도착 전에는 로딩 상태를 먼저 보여주고, 접근 시 옵셔널 체이닝과 기본값을 함께 쓰세요. 초기 상태를 빈 객체나 빈 배열로 두는 것도 방법입니다.

Q4?? 와 || 는 뭐가 다른가요?

|| 는 undefined·null뿐 아니라 0·빈 문자열·false 같은 falsy 값도 모두 대체합니다. ?? (널 병합)는 오직 undefined·null일 때만 대체하죠. 수량 0이나 빈 문자열을 유효한 값으로 살려야 한다면 ?? 를 쓰는 게 안전합니다.

Q5"of null" 에러는 또 뭔가요?

메시지는 같고 비어 있던 값이 null인 경우입니다. undefined가 "아직 안 채워짐"이라면 null은 "비었다고 의도적으로 표시함"이죠. querySelector가 요소를 못 찾으면 null을 반환하는 게 대표적입니다. 해결법(옵셔널 체이닝·널 병합)은 양쪽에 똑같이 통합니다.


📌 결론

"Cannot read properties of undefined (reading 'x')"는 undefined인 값에서 속성을 읽으려다 나는 TypeError다. 메시지의 (reading 'x')는 막힌 속성을, 진짜 빈 값은 그 한 단계 왼쪽을 가리킨다. 그래서 디버깅은 "막힌 속성의 왼쪽"을 들여다보는 데서 시작한다.

 

실무 원칙은 다음과 같다.

 

🔍 메시지를 정확히 읽는다. (reading 'x')의 x가 아니라 점 왼쪽 값이 undefined였다. 스택 추적으로 그 줄을 찾아 한 단계씩 확인한다.

🛡 옵셔널 체이닝으로 방어한다. ?.와 ?? 로 중첩 접근을 안전하게 만들되, 에러를 가리는 것과 데이터가 있는 건 다름을 기억한다.

⏳ 근본 원인을 고친다. 오타·미반환 함수·비동기 타이밍 중 무엇인지 짚고, 데이터 도착 전에는 로딩 상태와 초기값으로 막는다.

undefined 속성 에러 체크리스트

 

01(reading 'x')의 한 단계 왼쪽 값을 console.log로 확인.
02객체 경로 오타·중첩 단계 누락 점검.
03함수 return 누락·find() 미일치(undefined) 여부 확인.
04비동기면 로딩 상태·초기값(빈 객체·배열)로 가드.
05접근부엔 옵셔널 체이닝 ?. + 널 병합 ?? 적용.
06null 버전 에러면 querySelector 등 "의도적 빈 값" 의심.

본 글은 자바스크립트 TypeError의 일반적 원인과 해결 방법을 정리한 자료다. 코드 수정은 영향 범위를 확인한 뒤 신중히 적용한다.

 

#JavaScript #TypeError #Cannotreadproperties #undefined #자바스크립트에러 #옵셔널체이닝 #optionalchaining #널병합 #nullishcoalescing #프론트엔드 #JS디버깅 #런타임에러 #null과undefined #웹개발 #코딩초보

반응형

댓글