drizzle-team/drizzle-orm · error · Error

No value for placeholder "${p.value.name}" was provided

Error message

No value for placeholder "${p.value.name}" was provided

What it means

Thrown by fillPlaceholders() (sql.ts:624) for the same reason as 144, but the placeholder is wrapped inside a Param object that carries a custom column encoder (e.g. a typed placeholder bound to a column). Drizzle still needs the named value from the values map and throws when it is missing.

Source

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

/** @deprecated Use `sql.placeholder` instead. */
export function placeholder<TName extends string>(name: TName): Placeholder<TName> {
	return new Placeholder(name);
}

export function fillPlaceholders(params: unknown[], values: Record<string, unknown>): unknown[] {
	return params.map((p) => {
		if (is(p, Placeholder)) {
			if (!(p.name in values)) {
				throw new Error(`No value for placeholder "${p.name}" was provided`);
			}

			return values[p.name];
		}

		if (is(p, Param) && is(p.value, Placeholder)) {
			if (!(p.value.name in values)) {
				throw new Error(`No value for placeholder "${p.value.name}" was provided`);
			}

			return p.encoder.mapToDriverValue(values[p.value.name]);
		}

		return p;
	});
}

export type ColumnsSelection = Record<string, unknown>;

const IsDrizzleView = Symbol.for('drizzle:IsDrizzleView');

export abstract class View<
	TName extends string = string,
	TExisting extends boolean = boolean,
	TSelection extends ColumnsSelection = ColumnsSelection,
> implements SQLWrapper {

View on GitHub (pinned to b7862528fd)

Solutions

  1. Supply every placeholder name in the placeholderValues argument at execute time.
  2. Log the names of placeholders embedded in the query before executing to catch missing keys.
  3. Centralise placeholder-name constants to avoid drift between build and call sites.

Example fix

// before
const q = db.select().from(users)
  .where(sql`${users.id} = ${sql.placeholder('uid')}`).prepare();
await q.all({ wrong: 1 }); // throws

// after
await q.all({ uid: 1 });
Defensive patterns

Strategy: validation

Validate before calling

// same as 144: ensure every placeholder name (including those wrapped in Param/encoder)
// is present in the values object before calling execute/all/run.
function assertPlaceholders(names: string[], values: Record<string, unknown>) {
  const missing = names.filter((n) => !(n in values));
  if (missing.length) throw new Error('Missing placeholder values: ' + missing.join(', '));
}

Type guard

const hasAllKeys = (obj, keys: string[]) => keys.every((k) => k in obj);

Prevention

When it happens

Trigger: Using a column-bound placeholder (e.g. new Param(new Placeholder('x'), column)) — typically produced by passing a placeholder through a typed column context — then executing without supplying that name in placeholderValues.

Common situations: Building typed parameterised fragments with sql.placeholder inside typed column expressions; refactoring encoders; placeholders created indirectly through helper functions that wrap them in Param.

Related errors


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