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

  1. Pass a callback as the final argument: fs.fstat(fd, (err, stats) => {...}) or fs.fstat(fd, { bigint: true }, cb)
  2. If you want the result synchronously, use fs.fstatSync(fd) instead of fs.fstat(fd)
  3. 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

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


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)