I have an express app managed via PM2 deployed to an Ubuntu Server. At a certain point an endpoint receives and saves some files in this way
fs.access(path.join(__dirname, '..', 'static', 'images', 'users', userId), (error) => {
if (error) {
fs.mkdirSync(path.join(__dirname, '..', 'static', 'images', 'users', userId));
}
});
But the process crashes. From the logs I can see:
0|App | node:internal/fs/utils:344
0|App | throw err;
0|App | ^
0|App |
0|App | Error: ENOENT: no such file or directory, mkdir '/var/www/services.my-app.it/static/images/users/Vtk7xRzSU0fmaqyViTbv5ItQTXs2'
0|App | at Object.mkdirSync (node:fs:1334:3)
0|App | at /var/www/services.my-app.it/dist/index.js:1:11558
0|App | at FSReqCallback.oncomplete (node:fs:188:23) {
0|App | errno: -2,
0|App | syscall: 'mkdir',
0|App | code: 'ENOENT',
0|App | path: '/var/www/services.my-app.it/static/images/users/Vtk7xRzSU0fmaqyViTbv5ItQTXs2'
0|App | }
0|App | error Command failed with exit code 1.
It's clearly a permissions problem, however I can't figure out what is the user that needs the permission in order to solve the problem.
I tried to launch the process via pm2 start
both from root
and personal user, nothing changes.
▶ ll
total 312K
drwxr-xr-x 2 root root 4.0K May 4 12:15 dist
-rw-rw-r-- 1 thefe thefe 1.1K May 2 15:18 index.js
-rw-rw-r-- 1 thefe thefe 440 May 2 14:55 jsconfig.json
drwxrwxr-x 485 thefe thefe 20K May 2 14:56 node_modules
-rw-rw-r-- 1 thefe thefe 1.4K May 2 14:55 package.json
-rw-rw-r-- 1 thefe thefe 2.3K Apr 15 2022 service-account.json
drwxrwxr-x 7 thefe thefe 4.0K Apr 9 19:59 src
drwxrwxrwx 2 root root 4.0K May 4 09:48 static
-rw-rw-r-- 1 thefe thefe 1012 May 2 14:55 webpack.config.js
-rw-rw-r-- 1 thefe thefe 259K May 2 14:55 yarn.lock
Ok, I figured it out! It wasn't actually a permissions problem (that were configured correctly), but actually the { recursive: true }
was missing from the fs.mkdirSync
, and so Node wasn't able to create the subfolders. Adding that solved the problem.
UPDATED CODE IS:
fs.access(path.join(__dirname, '..', 'static', 'images', 'users', userId), (error) => {
if (error) {
fs.mkdirSync(path.join(__dirname, '..', 'static', 'images', 'users', userId), { recursive: true });
}
});
After some researches I found a new way to do what I'm doing with new NodeJS functions. I created a utility method, credits go to this answer
import { stat, mkdir } from 'node:fs/promises';
const checkAndMakeDir = async (dir) => {
try {
await stat(dir);
} catch (error) {
if (error.code === 'ENOENT') {
try {
await mkdir(dir, { recursive: true });
} catch (err) {
console.error(err.message);
}
}
}
};
export default checkAndMakeDir;