n8n-io/n8n · error · Error

Invalid timezone

Error message

Invalid timezone: "${timezone}"

What it means

buildContext validates the optional timezone argument against luxon's IANAZone.isValidZone before installing it as Settings.defaultZone. An unrecognized zone string (typo, abbreviation like 'CET', or non-IANA format) is rejected up front so date expressions don't silently fall back to the wrong zone.

Solutions

  1. Use a full IANA zone identifier, e.g. 'Europe/Berlin', not abbreviations like 'CET' or offsets
  2. Check the instance/workflow timezone setting — it is passed down to the expression runtime
  3. Verify the string for typos; zone names are case-sensitive per the IANA database
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/@n8n/expression-runtime/src/runtime/context.ts:112 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at packages/@n8n/expression-runtime/src/runtime/context.ts:112

 * Build a fresh, closure-scoped evaluation context.
 *
 * This function creates a context object that contains everything needed to
 * evaluate an expression, without touching any global mutable state
 * (except luxon's Settings.defaultZone which is process-wide).
 *
 * The returned object is used as tournament's `this` context in the
 * evalClosureSync wrapper.
 *
 * @param callbacks - Bridge callbacks (data-access primitives + typed RPCs)
 * @param timezone - Optional IANA timezone string
 * @returns A context object with all workflow data, proxies, and builtins
 */
export function buildContext(
	callbacks: BridgeCallbacks,
	timezone?: string,
): Record<string, unknown> {
	if (timezone && !IANAZone.isValidZone(timezone)) {
		throw new Error(`Invalid timezone: "${timezone}"`);
	}
	Settings.defaultZone = timezone ?? 'system';

	const target: Record<string, unknown> = {};

	// __sanitize must be on the context because PrototypeSanitizer generates:
	// obj[this.__sanitize(expr)] where 'this' is the context (via .call(ctx) wrapping)
	// Use a non-writable property descriptor so override attempts throw instead of silently succeeding.
	Object.defineProperty(target, '__sanitize', {
		get: () => __sanitize,
		set: () => {
			throw new ExpressionError('Cannot override "__sanitize" due to security concerns');
		},
		enumerable: false,
		configurable: false,
	});

	// -------------------------------------------------------------------------

View on GitHub (pinned to 5ac6606e81)