drizzle-team/drizzle-orm · error · Error

Cannot execute a query on a query builder. Please use a data

Error message

Cannot execute a query on a query builder. Please use a database instance instead.

What it means

Thrown in SingleStoreSelectBase.prepare (select.ts:992) when this.session is undefined. A select built via the query-builder factory ($drizzle.createQueryBuilder() / SingleStoreSelectBuilder without a session) has no database connection and therefore cannot be prepared or executed; only a SingleStoreDatabase instance (db.select(...)) carries a session.

Source

Thrown at drizzle-orm/src/singlestore-core/query-builders/select.ts:992

	TResult = SelectResult<TSelection, TSelectMode, TNullabilityMap>[],
	TSelectedFields = BuildSubquerySelection<TSelection, TNullabilityMap>,
> extends SingleStoreSelectQueryBuilderBase<
	SingleStoreSelectHKT,
	TTableName,
	TSelection,
	TSelectMode,
	TPreparedQueryHKT,
	TNullabilityMap,
	TDynamic,
	TExcludedMethods,
	TResult,
	TSelectedFields
> {
	static override readonly [entityKind]: string = 'SingleStoreSelect';

	prepare(): SingleStoreSelectPrepare<this> {
		if (!this.session) {
			throw new Error('Cannot execute a query on a query builder. Please use a database instance instead.');
		}
		const fieldsList = orderSelectedFields<SingleStoreColumn>(this.config.fields);
		const query = this.session.prepareQuery<
			SingleStorePreparedQueryConfig & { execute: SelectResult<TSelection, TSelectMode, TNullabilityMap>[] },
			TPreparedQueryHKT
		>(this.dialect.sqlToQuery(this.getSQL()), fieldsList, undefined, undefined, undefined, {
			type: 'select',
			tables: [...this.usedTables],
		}, this.cacheConfig);
		query.joinsNotNullableMap = this.joinsNotNullableMap;
		return query as SingleStoreSelectPrepare<this>;
	}

	$withCache(config?: { config?: CacheConfig; tag?: string; autoInvalidate?: boolean } | false) {
		this.cacheConfig = config === undefined
			? { config: {}, enable: true, autoInvalidate: true }
			: config === false
			? { enable: false }

View on GitHub (pinned to b7862528fd)

Solutions

  1. Use the database instance to build executable queries: `db.select(...).from(...)` instead of `qb.select(...)`.
  2. If you only need the SQL string from a builder, call .toSQL() (which does not require a session).
  3. Pass the db (or tx) into the function that needs to execute, not the bare query builder.

Example fix

// before
const qb = db.$with('qb');
const q = db.select({id: users.id}).from(users); // built from qb w/o session
await q.execute();
// after
const q = db.select({id: users.id}).from(users);
await q.execute();
Defensive patterns

Strategy: type-guard

Validate before calling

function isExecutable(select) {
  return Boolean(select.session);
}
if (!isExecutable(q)) throw new Error('Use db.select(), not a session-less query builder, to execute');

Type guard

function isRunnableSelect(q): boolean {
  return Boolean(q && q.session);
}

Prevention

When it happens

Trigger: Calling .execute(), .prepare(), or .iterator() on a select created via createQueryBuilder (the 'qb' builder mode) instead of via the db instance; passing a builder around and trying to run it directly.

Common situations: Using drizzle's query-builder API to compose SQL for inspection but accidentally calling execute on it; refactoring db access into a layer that receives a qb instead of db; confusing the query-builder (composition only) with the database (execution).

Related errors


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