discordjs/discord.js · error · TypeError

${defaultValueGenerator} is not a function

Error message

${defaultValueGenerator} is not a function

What it means

Collection.ensure(key, defaultValueGenerator) only calls the generator if the key is absent. To keep the contract that the second argument is a factory function, it throws a TypeError when the argument is not callable, stringifying the offending value into the message.

Source

Thrown at packages/collection/src/collection.ts:55

 *
 * @typeParam Key - The key type this collection holds
 * @typeParam Value - The value type this collection holds
 */
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
export class Collection<Key, Value> extends Map<Key, Value> {
	/**
	 * Obtains the value of the given key if it exists, otherwise sets and returns the value provided by the default value generator.
	 *
	 * @param key - The key to get if it exists, or set otherwise
	 * @param defaultValueGenerator - A function that generates the default value
	 * @example
	 * ```ts
	 * collection.ensure(guildId, () => defaultGuildConfig);
	 * ```
	 */
	public ensure(key: Key, defaultValueGenerator: (key: Key, collection: this) => Value): Value {
		if (this.has(key)) return this.get(key)!;
		if (typeof defaultValueGenerator !== 'function') throw new TypeError(`${defaultValueGenerator} is not a function`);
		const defaultValue = defaultValueGenerator(key, this);
		this.set(key, defaultValue);
		return defaultValue;
	}

	/**
	 * Checks if all of the elements exist in the collection.
	 *
	 * @param keys - The keys of the elements to check for
	 * @returns `true` if all of the elements exist, `false` if at least one does not exist.
	 */
	public hasAll(...keys: Key[]) {
		return keys.every((key) => super.has(key));
	}

	/**
	 * Checks if any of the elements exist in the collection.
	 *

View on GitHub (pinned to a81ed8a306)

Solutions

  1. Wrap the default in a function: collection.ensure(key, () => defaultValue).
  2. If you just want a stored value, use has/get/set instead of ensure.
  3. Check the JSDoc example in collection.ts: `collection.ensure(guildId, () => defaultGuildConfig)`.

Example fix

// before
collection.ensure(guildId, defaultGuildConfig);
// after
collection.ensure(guildId, () => defaultGuildConfig);
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof defaultValueGenerator !== 'function') {
  throw new TypeError('ensure() requires a factory function');
}

Type guard

function isFactory<V, K>(f: unknown): f is (key: K, collection: unknown) => V {
  return typeof f === 'function';
}

Try / catch

try {
  collection.ensure(key, def as any);
} catch (err) {
  if (err instanceof TypeError && err.message.includes('is not a function')) {
    collection.set(key, def);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling collection.ensure(key, value) passing a non-function as the second argument — e.g. ensure('cfg', defaultConfig) instead of ensure('cfg', () => defaultConfig).

Common situations: Misreading the API as an upsert-with-value method; refactoring from get-or-set code that used plain values; copying ensure() usage from Map patterns where a default value (not factory) is expected.

Related errors


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