n8n-io/n8n · error · ExpressionExtensionError

Unsupported format '${String(valueFormat)}'. toDateTime() su

Error message

Unsupported format '${String(valueFormat)}'. toDateTime() supports 'ms', 's', 'us' and 'excel'.

What it means

The NUMBER variant of `.toDateTime(format)` accepts only `'ms'`, `'s'`, `'us'`, and `'excel'` (milliseconds, seconds, microseconds, and days-since-1900 respectively). Any other format string throws; the four valid tokens are listed in the message. (The STRING variant of `.toDateTime()` is a different function and accepts Luxon format tokens.)

Source

Thrown at packages/@n8n/expression-runtime/src/extensions/number-extensions.ts:75

function toBoolean(value: number) {
	return value !== 0;
}

function toInt(value: number) {
	return round(value, []);
}

function toFloat(value: number) {
	return value;
}

type DateTimeFormat = 'ms' | 's' | 'us' | 'excel';
export function toDateTime(value: number, extraArgs: [DateTimeFormat]) {
	const [valueFormat = 'ms'] = extraArgs;

	if (!['ms', 's', 'us', 'excel'].includes(valueFormat)) {
		throw new ExpressionExtensionError(
			`Unsupported format '${String(valueFormat)}'. toDateTime() supports 'ms', 's', 'us' and 'excel'.`,
		);
	}

	switch (valueFormat) {
		// Excel format is days since 1900
		// There is a bug where 1900 is incorrectly treated as a leap year
		case 'excel': {
			const DAYS_BETWEEN_1900_1970 = 25567;
			const DAYS_LEAP_YEAR_BUG_ADJUST = 2;
			const SECONDS_IN_DAY = 86_400;
			return DateTime.fromSeconds(
				(value - (DAYS_BETWEEN_1900_1970 + DAYS_LEAP_YEAR_BUG_ADJUST)) * SECONDS_IN_DAY,
			);
		}
		case 's':
			return DateTime.fromSeconds(value);
		case 'us':

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Use one of `ms`, `s`, `us`, `excel` for numeric inputs.
  2. If the source is an ISO/date string, use the string `.toDateTime()` variant (or `.toDate()`) instead.
  3. Convert exotic epochs in a Code node (e.g. nanoseconds → milliseconds) before calling `.toDateTime('ms')`.

Example fix

// before
{{ $json.epochMicros.toDateTime('micros') }}
// after
{{ $json.epochMicros.toDateTime('us') }}
Defensive patterns

Strategy: validation

Validate before calling

const FORMATS = new Set(['ms','s','us','excel']);
const fmt = $json.fmt;
if (typeof $json.value === 'number' && !FORMATS.has(fmt)) {
  throw new Error(`toDateTime(): unsupported numeric format '${fmt}'`);
}
return $json;

Type guard

const isNumericDateTimeFormat = (f: string): f is 'ms'|'s'|'us'|'excel' =>
  ['ms','s','us','excel'].includes(f);

Prevention

When it happens

Trigger: Calling `.toDateTime('nanos')`, `.toDateTime('iso')`, or passing a Luxon token like `'yyyy'` on a numeric value.

Common situations: Copy-pasting a format token from the string variant; assuming arbitrary units are supported; passing a unit the source system uses but n8n does not.

Related errors


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