drizzle-team/drizzle-orm · error · Error

Unexpected param value: ${chunk}

Error message

Unexpected param value: ${chunk}

What it means

Thrown by SQL.mapInlineParam (sql.ts:322) when a value interpolated into a sql`` template cannot be inlined as a literal. The method handles null, number, boolean, string, and object; anything else (undefined, symbol, bigint, function) reaches the final throw. Inlining only happens for queries built with paramStyle 'inline' (e.g. sqlToQuery for dialects/databases that inline rather than bind placeholders).

Source

Thrown at drizzle-orm/src/sql/sql.ts:322

		{ escapeString }: BuildQueryConfig,
	): string {
		if (chunk === null) {
			return 'null';
		}
		if (typeof chunk === 'number' || typeof chunk === 'boolean') {
			return chunk.toString();
		}
		if (typeof chunk === 'string') {
			return escapeString(chunk);
		}
		if (typeof chunk === 'object') {
			const mappedValueAsString = chunk.toString();
			if (mappedValueAsString === '[object Object]') {
				return escapeString(JSON.stringify(chunk));
			}
			return escapeString(mappedValueAsString);
		}
		throw new Error('Unexpected param value: ' + chunk);
	}

	getSQL(): SQL {
		return this;
	}

	as(alias: string): SQL.Aliased<T>;
	/**
	 * @deprecated
	 * Use ``sql<DataType>`query`.as(alias)`` instead.
	 */
	as<TData>(): SQL<TData>;
	/**
	 * @deprecated
	 * Use ``sql<DataType>`query`.as(alias)`` instead.
	 */
	as<TData>(alias: string): SQL.Aliased<TData>;
	as(alias?: string): SQL<T> | SQL.Aliased<T> {

View on GitHub (pinned to b7862528fd)

Solutions

  1. Ensure the value is one of null/number/boolean/string/object before interpolating; coerce or guard against undefined.
  2. Use sql.placeholder() or bind parameters through .all()/.run() instead of inlining literals.
  3. If you genuinely need inline SQL, stringify/serialize unsupported types (BigInt -> String) before interpolation.

Example fix

// before
const q = sql`select * from t where id = ${maybeUndefined}`;
// maybeUndefined === undefined -> 'Unexpected param value: undefined'

// after
const id = maybeUndefined ?? null;
const q = sql`select * from t where id = ${id}`;
Defensive patterns

Strategy: validation

Validate before calling

function inlineSafe(value) {
  if (value === undefined) return null;
  if (typeof value === 'bigint') return value.toString();
  if (typeof value === 'symbol' || typeof value === 'function') {
    throw new TypeError('Cannot inline ' + typeof value);
  }
  return value;
}
// then: sql`... ${inlineSafe(maybeUndef)}`

Type guard

const isInlineable = (v): boolean =>
  v === null || ['number', 'boolean', 'string', 'object'].includes(typeof v);

Prevention

When it happens

Trigger: Interpolating undefined, a Symbol, a BigInt, or a function/class instance directly into sql`` and then building the query in inline-param mode (typical for SQLite/Prisma-style raw SQL or when using .toSQL() with invoke: 'inline'). Passing a custom column/SQL object whose toString() is not enough is fine, but a bare undefined is the classic trigger.

Common situations: A conditional that left a variable as undefined; a JSON field whose value was stripped to undefined; upgrading drizzle where the default param-inlining behaviour changed; passing a Date to an inline-built query on a path that does not special-case it.

Related errors


AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03). Data as JSON: /data/errors/1af64189ad1bbc9c.json. Report an issue: GitHub.