discordjs/discord.js · error · DiscordjsTypeError

InvalidType

InvalidType

Error message

Supplied ${name} is not a${an ? 'n' : ''} ${expected}.

What it means

Generic typed-argument validation from DiscordjsTypeError: a constructor option or argument was passed with the wrong JavaScript type. In Collector's constructor the specific throw is options.filter not being a function, but the same code template is used across the library for any `is not a <expected>` mismatch.

Source

Thrown at packages/discord.js/src/structures/interfaces/Collector.js:101

    /**
     * Timeout for cleanup due to inactivity
     *
     * @type {?Timeout}
     * @private
     */
    this._idletimeout = null;

    /**
     * The reason the collector ended
     *
     * @type {?string}
     * @private
     */
    this._endReason = null;

    if (typeof this.filter !== 'function') {
      throw new DiscordjsTypeError(ErrorCodes.InvalidType, 'options.filter', 'function');
    }

    this.handleCollect = this.handleCollect.bind(this);
    this.handleDispose = this.handleDispose.bind(this);

    if (options.time) this._timeout = setTimeout(() => this.stop('time'), options.time).unref();
    if (options.idle) this._idletimeout = setTimeout(() => this.stop('idle'), options.idle).unref();

    /**
     * The timestamp at which this collector last collected an item
     *
     * @type {?number}
     */
    this.lastCollectedTimestamp = null;
  }

  /**
   * The Date at which this collector last collected an item

View on GitHub (pinned to a81ed8a306)

Solutions

  1. Pass a function to options.filter, e.g. filter: (msg) => msg.author.id === userId.
  2. If your condition data is an object, wrap it: filter: makePredicate(myConfig) instead of filter: myConfig.
  3. Check property spelling and that no earlier assignment replaced filter with a non-function.
  4. In TypeScript, rely on CollectorOptions typing; remove `any` casts so the compiler flags non-function filters.

Example fix

// before
const collector = channel.createMessageCollector({ filter: { author: userId } });

// after
const collector = channel.createMessageCollector({ filter: (msg) => msg.author.id === userId });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof options?.filter !== 'function') {
  throw new TypeError('options.filter must be a function');
}

Type guard

function hasValidFilter(options) {
  return typeof options?.filter === 'function';
}

Try / catch

let collector;
try {
  collector = channel.createMessageCollector({ filter: (m) => m.author.id === userId });
} catch (err) {
  if (err?.name === 'TypeError' && /InvalidType/.test(err.message)) {
    console.error('filter must be a function');
  } else throw err;
}

Prevention

When it happens

Trigger: Calling createMessageCollector / createInteractionCollector / new Collector(...) with options.filter undefined, a truthy non-function (e.g. an object like { member: ... } passed where a predicate is expected), a misspelled property (filters instead of filter), or a filter accidentally overwritten by a boolean/string.

Common situations: Refactoring a filter into a config object and forgetting to wrap it in a function; copying code where `filter:` got minified/renamed; passing await results (a collection) instead of a predicate; TypeScript users bypassing types with `as any`.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30). Data as JSON: /api/errors/f68fc1864bafcd1a. Report an issue: GitHub.