hexojs/hexo · error · TypeError

fn must be a function

Error message

fn must be a function

What it means

Thrown by Box.addProcessor when the resolved processor callback is not a function. Hexo's Box registers functions that process files matched by a pattern; the call form shifts arguments so a lone function arg becomes the processor with the default pattern. If no usable function is found, this guard rejects the registration as a programmer error.

Source

Thrown at lib/box/index.ts:100

          path: this.source
        }, options);
      }
    }

    _File.prototype.box = this;

    return _File;
  }

  addProcessor(pattern: (...args: any[]) => any): void;
  addProcessor(pattern: string | RegExp | Pattern | ((str: string) => any), fn: (...args: any[]) => any): void;
  addProcessor(pattern: string | RegExp | Pattern | ((str: string) => any), fn?: (...args: any[]) => any): void {
    if (!fn && typeof pattern === 'function') {
      fn = pattern;
      pattern = defaultPattern;
    }

    if (typeof fn !== 'function') throw new TypeError('fn must be a function');
    if (!(pattern instanceof Pattern)) pattern = new Pattern(pattern);

    this.processors.push({
      pattern,
      process: fn
    });
  }

  _readDir(base: string, prefix = ''): BlueBirdPromise<string[]> {
    const { context: ctx } = this;
    const results: string[] = [];
    return readDirWalker(ctx, base, results, this.ignore, prefix)
      .return(results)
      .map(path => this._checkFileStatus(path))
      .map(file => this._processFile(file.type, file.path).return(file.path));
  }

  _checkFileStatus(path: string): { type: string; path: string } {

View on GitHub (pinned to 059cb17494)

Solutions

  1. Pass the processor as a function: box.addProcessor(/\.md$/, file => { ... }) or box.addProcessor(file => { ... }).
  2. Verify the imported handler symbol is defined and is a function before registering (check for undefined from a broken import).
  3. If using the pattern+fn form, ensure the SECOND argument is the function, not a string/object.

Example fix

// before
box.addProcessor(/\.md$/, undefined);
// after
box.addProcessor(/\.md$/, file => { /* ... */ });
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof handler !== 'function') throw new Error('handler must be a function');
box.addProcessor(/\.md$/, handler);

Type guard

const isProcessorFn = (x: unknown): x is (...a: any[]) => any => typeof x === 'function';

Prevention

When it happens

Trigger: Calling box.addProcessor('/\.md$/') (pattern string with no second fn argument), box.addProcessor(undefined), or box.addProcessor(pattern, null) where the second argument is not a function.

Common situations: A plugin or theme script registers a processor but the imported handler resolved to undefined (bad import path, cyclic import), or the author passed a config object instead of a function, or forgot the callback in the two-argument form.

Related errors


AI-assisted analysis of hexojs/hexo@059cb17494 (2026-08-12). Data as JSON: /api/errors/1237d07fe9f37db8. Report an issue: GitHub.