javascriptnode.jsunit-testingfilenode.js-fs

Why Can This Not Write To Directory 'Output'?


I am attempting to write a file to an existing directory, using node, path, and fs.

How it's supposed to work:

  1. Init mock data.
  2. Loop through mock data.
  3. Write mock string to existing directory 'output'
  4. End program.

How it's working:

  1. Init mock data.
  2. Loop through mock data.
  3. Attempt to write to existing directory.
  4. Yield error:

Error:

throw new Error(`Error writing: ${err.message}`);
                                ^

Error: Error writing: ENOENT: no such file or directory, open 'C:\Users\username\test\cheerio\output\55-207-0-228_2025-04-29_15:27:51.txt'
    at C:\Users\username\test\cheerio\components\WriteFile.js:31:11
    at node:fs:2385:7
    at FSReqCallback.oncomplete (node:fs:188:23)

Repository

I'm working off this repository. The function handling node:fs writefile is found at /component/WriteFile.js; it is being invoked here, on these lines..

Project Tree

This is the project structure:

project-root/
├── components/             
├── node_modules/            
├── output/                  // Target for file write. 
├── .gitignore               
├── index.js               
├── LICENSE                 
├── package-lock.json        
├── package.json            
└── README.md                

WriteFile Snippet

Posting relevant code here for convenience. WriteFile.js

const fs = require('node:fs');
const path = require('path');

const makeFile = async (fileName, { contentString, ip }) => {
    const now = new Date();
    const dateString =
        now.getFullYear() +
        '-' +
        String(now.getMonth() + 1).padStart(2, '0') +
        '-' +
        String(now.getDate()).padStart(2, '0') +
        '_' +
        String(now.getHours()).padStart(2, '0') +
        ':' +
        String(now.getMinutes()).padStart(2, '0') +
        ':' +
        String(now.getSeconds()).padStart(2, '0');

    contentString = `DATE: ${dateString}\nFor ip: ${ip}\n${contentString}`;

    const filepath = path.join(
        __dirname,
        '..',
        'output',
        `${fileName}_${dateString}.txt`
    );

    try {
        await fs.writeFile(filepath, contentString, 'utf16le', (err) => {
            if (err) {
                throw new Error(`Error writing: ${err.message}`);
            }
        });
        return 'Success';
    } catch (error) {
        console.error('\nError:\n', error.message, '\n');
    } finally {
        // Code that will run regardless of try/catch result
        // Remember, don't have a return in finally.
        console.log('Final completed.');
    }
};

module.exports = { makeFile };

Invoked At:

Which is being called at:

async function main() {
    let start = performance.now();
    let elapse;
    i = 0;
    for (const ip of ipList) {
        i++;
        if (i > 3) {
            break;
        }
        const sleep = (ms) =>
            new Promise((resolve) => {
                setTimeout(resolve, ms);
            });
        await sleep(500);

        await makeFile(ip.replaceAll('.', '-'), {
            contentString: 'Mockdata',
            ip: ip
        });
    }
    elapse = performance.now() - start;
    console.log('Total time elapsed: ', elapse / 1000);
}

Solution

  • Colon character in 55-207-0-228_2025-04-29_15:27:51.txt is invalid on Windows. The question doesn't mention the platform, but file path presumes this.

    It should be:

        String(now.getHours()).padStart(2, '0') +
        '-' +
        String(now.getMinutes()).padStart(2, '0') +
        '-' +
        String(now.getSeconds()).padStart(2, '0');
    

    output directory is not guaranteed to exist because it doesn't exist in the repo. Even if it exists in the current project, there needs to be mkdir to make it consistently working.

    Use node:fs/promises instead of node:fs if you want to use it with async..await, there naturally will be problems in the order of execution and error handling otherwise.