n8n-io/n8n · error · ExpressionExtensionError

${functionName}() is only callable on types ${typeNames}

Error message

${functionName}() is only callable on types ${typeNames}

What it means

When the requested method name exists on MORE THAN ONE extension type but the input's own type does not provide it, n8n enumerates the types it IS available on, formatted as `"A", "B", and "C"`. This is the multi-type variant of the dispatch-failure branch.

Source

Thrown at packages/@n8n/expression-runtime/src/extensions/extend.ts:155

 */
export function extend(input: unknown, functionName: string, args: unknown[]) {
	const foundFunction = findExtendedFunction(input, functionName);

	// No type specific or generic function found. Check to see if
	// any types have a function with that name. Then throw an error
	// letting the user know the available types.
	if (!foundFunction) {
		checkIfValueDefinedOrThrow(input, functionName);
		const haveFunction = EXTENSION_OBJECTS.filter((v) => functionName in v.functions);
		if (!haveFunction.length) {
			// This shouldn't really be possible but we should cover it anyway
			throw new ExpressionExtensionError(`Unknown expression function: ${functionName}`);
		}

		if (haveFunction.length > 1) {
			const lastType = `"${haveFunction.pop()!.typeName}"`;
			const typeNames = `${haveFunction.map((v) => `"${v.typeName}"`).join(', ')}, and ${lastType}`;
			throw new ExpressionExtensionError(
				`${functionName}() is only callable on types ${typeNames}`,
			);
		} else {
			throw new ExpressionExtensionError(
				`${functionName}() is only callable on type "${haveFunction[0].typeName}"`,
			);
		}
	}

	if (foundFunction.type === 'native') {
		// eslint-disable-next-line @typescript-eslint/no-unsafe-return
		return foundFunction.function.apply(input, args);
	}

	// eslint-disable-next-line @typescript-eslint/no-unsafe-return
	return foundFunction.function(input, args);
}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Convert the value to one of the listed types first (`.toString()`, `.toNumber()`, `.toDateTime()`).
  2. Use a method that is actually defined for the current value's type.
  3. Inspect the upstream node output to confirm the runtime type.

Example fix

// before (count is a number, but the method needs a string)
{{ $json.count.someSharedMethod() }}
// after
{{ $json.count.toString().someSharedMethod() }}
Defensive patterns

Strategy: type-guard

Validate before calling

// Confirm the value's runtime type matches one of the types listed in the error before calling the method:
const t = Array.isArray($json.x) ? 'array' : $json.x instanceof Date ? 'date' : typeof $json.x;
if (!['string','number'].includes(t)) {
  throw new Error(`Method not available on type: ${t}`);
}
return $json;

Type guard

const isStringOrNumber = (v: unknown): v is string | number =>
  typeof v === 'string' || typeof v === 'number';

Prevention

When it happens

Trigger: Calling a method that exists for several types but not for the current value's type — e.g. calling a string/number-shared method on a plain object.

Common situations: Type mismatch in the expression; assuming a method works on any value; upstream node returned an unexpected type (object vs primitive).

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/e9e6281e915b2cce. Report an issue: GitHub.