[Nodejs] TypeError: Cannot convert undefined or null to object

2023. 3. 7. 17:11공부 중/Node.js

1. 현상

 

와 Docker를 배워서 이미지를 만들어서 github container registry에 업로드했다.

 

신이 나버린 나는 당연히 다른 PC를 켜서 도커를 설치하고 git clone, docker-compose up을 했다.

 

하지만 나의 기대와는 다르게 도커는 “운영체제가 달라 저리 치워”라고 말했다.

 

나는 도커의 비위를 맞춰 bulidx를 이용해서 멀티 플랫폼으로 빌드했고 다시 Compose up을 했다.

 

그랬는데… 이 놈이 이번에는 JS 문법 오류가 있다고 에러를 낸다.

 

아니 맥북에서는 잘만 돌아가는데 왜 이러냐…

 

에러 메시지는 다음과 같다.

 

study_nodejs-studynode-1  | TypeError: Cannot convert undefined or null to object
study_nodejs-studynode-1  |     at Function.keys (<anonymous>)
study_nodejs-studynode-1  |     at Object.List (/app/src/lib/template.js:34:32)
study_nodejs-studynode-1  |     at /app/src/main.js:21:29
study_nodejs-studynode-1  |     at FSReqCallback.oncomplete (node:fs:197:23)

에러 코드를 기반으로 원인을 추측해 보자.

 

코드를 수정하고 실행해 본다.

 

List : function(filelist) {
    let list = "<ul>";
        if(Array.isArray(filelist)){
            for (let i = 0; i < Object.keys(filelist).length; i++) {
              list += `<li><a href="/?id=${filelist[i]}">${filelist[i]}</a></li>`;
            }
            list += "</ul>";
            return list;
        }else{
            return `filelist is not a array. filelist is ${typeof filelist}.`;
        }
}

 

맥북에서 PC에서의 차이점은 readdir로 읽어서 array에 전달될 data/ 아래의 파일들이 없다는 것이다.

 

  • 게시판에 새 글을 작성해 본다.

 

글이 작성되고 title은 보이지만 내용이 비어있다.

 

이는 곧 파일이 생성되지 않았음을 의미한다.

 

실제 디렉터리를 보아도 그렇다.

 

~/D/Study_nodeJS/src | mysql !1  ls -al                                                              ok | 02:16:31 AM
total 24
drwxr-xr-x 3 fkaus4598 fkaus4598 4096 Mar  6 01:44 .
drwxr-xr-x 8 fkaus4598 fkaus4598 4096 Mar  6 02:05 ..
drwxr-xr-x 2 fkaus4598 fkaus4598 4096 Mar  6 02:07 lib
-rw-r--r-- 1 fkaus4598 fkaus4598 6515 Mar  4 19:17 main.js
-rw-r--r-- 1 fkaus4598 fkaus4598  734 Mar  4 19:04 style.css
// data 디렉터리가 생성되지 않았다.

 

  • 빈 data 디렉터리를 생성한다.

혹시 readdir, writeFile 등 동작에 실행 주소로 설정된 data 디렉터리가 없어서 그런 것이 아닐까 생각이 들었다.

~/D/Study_nodeJS/src | mysql !1  mkdir data                                      ok | 02:22:58 AM 

 ~/D/Study_nodeJS/src | mysql !1  ll                                              ok | 02:23:03 AM 
total 28
drwxr-xr-x 4 fkaus4598 fkaus4598 4096 Mar  6 02:23 .
drwxr-xr-x 8 fkaus4598 fkaus4598 4096 Mar  6 02:05 ..
drwxr-xr-x 2 fkaus4598 fkaus4598 4096 Mar  6 02:23 data
drwxr-xr-x 2 fkaus4598 fkaus4598 4096 Mar  6 02:07 lib
-rw-r--r-- 1 fkaus4598 fkaus4598 6515 Mar  4 19:17 main.js
-rw-r--r-- 1 fkaus4598 fkaus4598  734 Mar  4 19:04 style.css

 

 

그렇다… 경로로 설정한 디렉터리가 없어서 그랬던 거였구나…

 

나머지 기능들도 정상적으로 동작한다.

 

 


2. 해결책

 

가. .gitkeep

 

github에 data 디렉터리가 올라가길 원하지 않아서 .gitignore에 추가한 것이 문제가 될 줄은 몰랐다.

 

그래서 마지막으로 .gitignore를 수정하고 해당 버그에 대해서 test 코드를 추가해 보았다.

 

# /app/src/test/main.test.js
const fs = require('fs');
const dataDir = "/app/src/data";

test('filelist is defined.', async()=>{
    const filelist = await fs.readdir(dataDir, (err, filelist)=>{
        return filelist;
    });
});
# .gitignore
# data/ -> data/*
./src/data/*

슬프게도 github는 비어있는 디렉터리는 아예 포함시키지 않는다.

 

.gitkeep을 사용해서 디렉터리를 유지하는 방법도 있지만 그러면 .gitkeep이 우리 홈페이지에 노출된다.

 

그냥 data 디렉터리가 없으면 생성하는 코드를 추가하자.

 


나. fs.accessSync

 

 

File system | Node.js v19.7.0 Documentation

 

nodejs.org

fs.existsSync는 더 이상 사용할 수 없다.

 

대신에 fs.accessSync를 활용할 수 있다.??

 

 

File system | Node.js v19.7.0 Documentation

 

nodejs.org

fs.accessSync(path[, mode])
- path <string> | <Buffer> | <URL>
- mode <integer> Default: fs.constants.F_OK
  • F_OK : Check if the file exists in the current directory.
  • R_OK : Check if the file is readable.
  • W_OK : Check if the file is writable.
  • constants.R_OK | constants.W_OK : Check if the file is readable and writable.

 

Do not use fs.access() to check for the accessibility of a file before calling fs.open()
, fs.readFile(), or fs.writeFile(). Doing so introduces a race condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file is not accessible.

 

 

어..? fs.open, fs.readFile, fs.writeFile 사용 전에 확인용으로 사용하기를 추천하지 않는다.

 

그냥 파일에 접근했을 때 발생하는 오류를 직접 핸들링하는 편이 더 좋다고 합니다.

 


다. if (err)

 

예외처리가 참 중요하구나…

 

아래는 JS 에러 객체에 대한 설명이다.

 

 

Error - JavaScript | MDN

Error 객체는 런타임 오류가 발생했을 때 던져집니다. Error 객체를 사용자 지정 예외의 기반 객체로 사용할 수도 있습니다. 아래 표준 내장 오류 유형을 참고하세요.

developer.mozilla.org

fs.readdir(path, function (err, filelist) {
    const noData = `ENOENT: no such file or directory, scandir '/app/src/data'`;
  if (err && err.message === noData){
        fs.mkdirSync(path, {recursive: true});
        filelist = [""];
    }
    ...

 

이제 잘 동작한다.

 


'공부 중 > Node.js' 카테고리의 다른 글

[Node.js] npm install mysql2  (0) 2023.03.13
[Node.js] MySQL 제어하기  (0) 2023.03.10
[Jest] Setup and Teardown  (0) 2023.03.01
[Jest] Testing Asynchronous Code  (0) 2023.03.01
[Jest] Matcher  (0) 2023.03.01