Promise error handling

I have some node code to create a new file only if that file doesn’t already exist.


'use strict';

const fs = require('fs');
const fsp = require('fs').promises;

const stuffToIgnore = `__tests__ \n`;

function npmIgnore() {
	return new Promise((resolve, reject) => {
		fsp.access(`.npmignore`, fs.constants.F_OK)
		.then(() => {resolve()})
		.catch((err) => {
			if (err.code === 'ENOENT') {
				fs.writeFile(`.npmignore`, stuffToIgnore)
			}
			else {
				reject(err);
			}
		});
	});
}

npmIgnore()
.catch(err => console.log(err));

I am getting the following errors in my console:

(node:75246) UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
    at maybeCallback (fs.js:127:9)
    at Object.writeFile (fs.js:1123:14)
    at fsp.access.then.catch (/Users/owo3732/random/fsnode/index.js:14:8)
(node:75246) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:75246) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

What am I doing wrong?

Edit: I tried rewriting this. I think the return new Promise bit was unnecessary

function npmIgnore() {
	return fsp.access(`.npmignore`, fs.constants.F_OK)
		.catch((err) => {
			if (err.code === 'ENOENT') {
				fsp.writeFile(`.npmignore`, stuffToIgnore)
			}
			else {
				reject(err);
			}
		});
}

Yes, fs/promises already has everything promisified. As fs.promises.writeFile() returns a promise as well, you should catch that too though:

const fs = require('fs')
const fsp = fs.promises

fsp.access('./.npmignore', fs.constants.F_OK)
  .catch(err => {
    if (err.code === 'ENOENT') {
      console.log(err.path + ' does not exist, creating...')
      return fsp.writeFile(err.path, 'stuff_to_ignore')
    }
  })
  .catch(console.error)
2 Likes

With my code I was able to do (for example purposes)

npmIgnore()
.then(() => console.log('done'))
.catch(err => console.log(err));

When I tried to do that with your code I got Cannot read property 'then' of undefined. Why is that?

Sounds like you forgot to return the promise from npmIgnore()… this would work though:

const fs = require('fs')
const fsp = fs.promises

const npmIgnore = stuffToIgnore => fsp
  .access('./.npmignore', fs.constants.F_OK)
  .catch(err => {
    if (err.code === 'ENOENT') {
      console.log(err.path + ' does not exist, creating...')
      return fsp.writeFile(err.path, stuffToIgnore)
    }
  })

npmIgnore('stuff_to_ignore')
  .then(() => console.log('done'))
  .catch(console.error)

Yes, the problem was that I copied and pasted your code and stuck it in the function but did not use the return keyword in front of fsp.access('./.npmignore', fs.constants.F_OK)

What difference does it make to the code whether you do or don’t return fsp.writeFile(err.path, stuffToIgnore)?

Well fs.promises.writeFile() gives you a promise, which you have to return if you want to chain additional handlers to npmIgnore(); otherwise it would just return undefined.

Could fsp.access('./.npmignore', fs.constants.F_OK) potentially error with something other than ENOENT? - in which case won’t that error be swallowed?

Hm just had to look that up too, it seems that the ENOENT condition is indeed redundant as the F_OK mode only checks for the file’s very existence (see here).

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.