n8n-io/n8n · error · TypeORMError

QueryBuilder parameter keys may only contain numbers, letter

Error message

QueryBuilder parameter keys may only contain numbers, letters, underscores, or periods.

What it means

QueryBuilder.setParameter() validates the key against /^([A-Za-z0-9_.]+)$/ and throws if it fails. Parameter keys become placeholders in generated SQL; characters outside alphanumerics, underscore, and period would break parameter substitution or risk injection. Keys like 'a b', 'a-b', 'a$b' are rejected.

Source

Thrown at packages/@n8n/typeorm/src/query-builder/QueryBuilder.ts:363

	 */
	hasParameter(key: string): boolean {
		return this.parentQueryBuilder?.hasParameter(key) || key in this.expressionMap.parameters;
	}

	/**
	 * Sets parameter name and its value.
	 *
	 * The key for this parameter may contain numbers, letters, underscores, or periods.
	 */
	setParameter(key: string, value: any): this {
		if (typeof value === 'function') {
			throw new TypeORMError(
				`Function parameter isn't supported in the parameters. Please check "${key}" parameter.`,
			);
		}

		if (!key.match(/^([A-Za-z0-9_.]+)$/)) {
			throw new TypeORMError(
				'QueryBuilder parameter keys may only contain numbers, letters, underscores, or periods.',
			);
		}

		if (this.parentQueryBuilder) {
			this.parentQueryBuilder.setParameter(key, value);
		}

		this.expressionMap.parameters[key] = value;
		return this;
	}

	/**
	 * Adds all parameters from the given object.
	 */
	setParameters(parameters: ObjectLiteral): this {
		for (const [key, value] of Object.entries(parameters)) {
			this.setParameter(key, value);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Use only letters, digits, underscore, and period in parameter keys.
  2. Sanitize dynamic keys: key.replace(/[^A-Za-z0-9_.]/g, '_').
  3. Prefer camelCase or snake_case keys consistently.
  4. If a hyphenated identifier is needed, alias it to a safe key and map back.

Example fix

// before
qb.andWhere('u.role = :user-role', {})
  .setParameter('user-role', role); // throws

// after
qb.andWhere('u.role = :userRole', {})
  .setParameter('userRole', role);
Defensive patterns

Strategy: validation

Validate before calling

const PARAM_KEY = /^([A-Za-z0-9_.]+)$/;
function isValidParamKey(key: string): boolean { return PARAM_KEY.test(key); }
if (!isValidParamKey(key)) throw new Error(`invalid parameter key: ${key}`);
function sanitizeParamKey(key: string): string { return key.replace(/[^A-Za-z0-9_.]/g, '_'); }

Type guard

function isValidParamKey(key: string): key is string {
  return /^([A-Za-z0-9_.]+)$/.test(key);
}

Prevention

When it happens

Trigger: Calling .setParameter('user id', val) (space), .setParameter('user-id', val) (hyphen), or any key with special characters. Also when building keys dynamically from untrusted input that contains symbols.

Common situations: Constructing parameter keys from form field names that contain spaces or hyphens. Copying a column name verbatim as a key. Typos or copy-paste introducing invisible characters.

Related errors


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