denoland/deno · error · Error
No callback function supplied
Error message
No callback function supplied
What it means
The Node-compat fs.fstat(fd, [options], callback) polyfill requires a callback function. The wrapper accepts either (fd, callback) or (fd, options, callback); if neither the second nor third argument is a function (i.e. optionsOrCallback/maybeCallback are both non-functions, typically undefined), it throws this synchronous Error before any I/O happens. This mirrors Node's rule that every async fs API must be given a callback; the synchronous variant is fs.fstatSync(fd[, options]).
Solutions
- Pass a callback as the final argument: fs.fstat(fd, (err, stats) => {...}) or fs.fstat(fd, { bigint: true }, cb)
- If you want the result synchronously, use fs.fstatSync(fd) instead of fs.fstat(fd)
- Double-check argument order when an options object is present: (fd, options, callback), never (fd, callback, options)
Example fix
// before
fs.fstat(fd); // throws: No callback function supplied
// after (async with options)
fs.fstat(fd, { bigint: true }, (err, stats) => {
if (err) throw err;
console.log(stats.size);
});
// or sync
const stats = fs.fstatSync(fd); Defensive patterns
Strategy: validation
Validate before calling
if (typeof maybeCb !== 'function' && typeof optsOrCb !== 'function') { throw new TypeError('fs.fstat requires a callback; use fstatSync for sync'); } Type guard
const isCallback = (v) => typeof v === 'function';
Try / catch
try { fs.fstat(fd, opts, cb); } catch (e) { /* thrown synchronously before I/O: fix the call site, don't retry */ throw e; } Prevention
- Prefer the fs.promises.* or *Sync variants so the callback problem disappears
- In wrappers, normalize overloads once: const cb = typeof a === 'function' ? a : b; if (!cb) throw ...
- Type your wrapper signatures as (fd: number, cb: (err, stats) => void) so TS flags missing callbacks at compile time
When it happens
Trigger: Calling fs.fstat(fd) with no further arguments; calling fs.fstat(fd, { bigint: true }) and forgetting the callback; passing the callback as the second argument while an options object occupies the callback slot, or spreading arguments in the wrong order.
Common situations: Porting fs.fstatSync code to the async API and forgetting the callback; refactoring a wrapper that sometimes passes options and sometimes a callback; copy-pasting a stat() call and renaming it to fstat() without updating the signature.
Related errors
- No callback function supplied
- No callback function supplied
- No callback function supplied
- ERR_INVALID_ARG_TYPE
- ERR_INVALID_ARG_VALUE
AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20).
Data as JSON: /api/errors/9defa08fcb461895.
Report an issue: GitHub.
Appendix: source
Thrown at ext/node/polyfills/_fs/_fs_fstat.ts:63
isFifo: stat.isFifo,
isSocket: stat.isSocket,
};
}
function fstat(
fd,
optionsOrCallback,
maybeCallback,
) {
fd = lazyFsUtils().getValidatedFd(fd);
const callback = typeof optionsOrCallback === "function"
? optionsOrCallback
: maybeCallback;
const options = typeof optionsOrCallback === "object"
? optionsOrCallback
: { bigint: false };
if (!callback) throw new Error("No callback function supplied");
PromisePrototypeThen(
op_node_fs_fstat(fd),
(stat) =>
callback(
null,
lazyStatUtils().CFISBIS(nodeFsStatToFileInfo(stat), options.bigint),
),
(err) => callback(denoErrorToNodeError(err, { syscall: "fstat" })),
);
}
function fstatSync(
fd,
options,
) {
fd = lazyFsUtils().getValidatedFd(fd);
try {View on GitHub (pinned to 9ad36f7a2c)