Skip to content

Commit c29734c

Browse files
addaleaxtargos
authored andcommitted
fs: improve fs.watch ENOSPC error message
Providing `No space left on device` is misleading in this case. Replace it with something that describes it more accurately. Refs: https://stackoverflow.com/questions/22475849/node-js-error-enospc/32600959 PR-URL: #21846 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]> Reviewed-By: Sakthipriyan Vairamani <[email protected]>
1 parent 9de6b26 commit c29734c

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

lib/internal/errors.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ function getMessage(key, args) {
249249
*/
250250
function uvException(ctx) {
251251
const [ code, uvmsg ] = errmap.get(ctx.errno);
252-
let message = `${code}: ${uvmsg}, ${ctx.syscall}`;
252+
let message = `${code}: ${ctx.message || uvmsg}, ${ctx.syscall}`;
253253

254254
let path;
255255
let dest;

lib/internal/fs/watchers.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const {
66
StatWatcher: _StatWatcher
77
} = process.binding('fs');
88
const { FSEvent } = process.binding('fs_event_wrap');
9+
const { UV_ENOSPC } = process.binding('uv');
910
const { EventEmitter } = require('events');
1011
const {
1112
getStatsFromBinding,
@@ -164,7 +165,9 @@ FSWatcher.prototype.start = function(filename,
164165
const error = errors.uvException({
165166
errno: err,
166167
syscall: 'watch',
167-
path: filename
168+
path: filename,
169+
message: err === UV_ENOSPC ?
170+
'System limit for number of file watchers reached' : ''
168171
});
169172
error.filename = filename;
170173
throw error;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const child_process = require('child_process');
5+
const stream = require('stream');
6+
7+
if (!common.isLinux)
8+
common.skip('The fs watch limit is OS-dependent');
9+
if (!common.enoughTestCpu)
10+
common.skip('This test is resource-intensive');
11+
12+
const processes = [];
13+
const gatherStderr = new stream.PassThrough();
14+
gatherStderr.setEncoding('utf8');
15+
gatherStderr.setMaxListeners(Infinity);
16+
17+
let finished = false;
18+
function spawnProcesses() {
19+
for (let i = 0; i < 10; ++i) {
20+
const proc = child_process.spawn(
21+
process.execPath,
22+
[ '-e',
23+
`process.chdir(${JSON.stringify(__dirname)});
24+
for (const file of fs.readdirSync('.'))
25+
fs.watch(file, () => {});`
26+
], { stdio: ['inherit', 'inherit', 'pipe'] });
27+
proc.stderr.pipe(gatherStderr);
28+
processes.push(proc);
29+
}
30+
31+
setTimeout(() => {
32+
if (!finished && processes.length < 200)
33+
spawnProcesses();
34+
}, 100);
35+
}
36+
37+
spawnProcesses();
38+
39+
let accumulated = '';
40+
gatherStderr.on('data', common.mustCallAtLeast((chunk) => {
41+
accumulated += chunk;
42+
if (accumulated.includes('Error:') && !finished) {
43+
assert(
44+
accumulated.includes('ENOSPC: System limit for number ' +
45+
'of file watchers reached'),
46+
accumulated);
47+
console.log(`done after ${processes.length} processes, cleaning up`);
48+
finished = true;
49+
processes.forEach((proc) => proc.kill());
50+
}
51+
}, 1));

0 commit comments

Comments
 (0)