Skip to content

Commit 13245dc

Browse files
committed
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 ee31c28 commit 13245dc

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

lib/internal/errors.js

Lines changed: 1 addition & 1 deletion
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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {
77
StatWatcher: _StatWatcher
88
} = process.binding('fs');
99
const { FSEvent } = internalBinding('fs_event_wrap');
10+
const { UV_ENOSPC } = internalBinding('uv');
1011
const { EventEmitter } = require('events');
1112
const {
1213
getStatsFromBinding,
@@ -165,7 +166,9 @@ FSWatcher.prototype.start = function(filename,
165166
const error = errors.uvException({
166167
errno: err,
167168
syscall: 'watch',
168-
path: filename
169+
path: filename,
170+
message: err === UV_ENOSPC ?
171+
'System limit for number of file watchers reached' : ''
169172
});
170173
error.filename = filename;
171174
throw error;
Lines changed: 51 additions & 0 deletions
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)