drizzle-team/drizzle-orm · error · Error
values() must be called with at least one value
Error message
values() must be called with at least one value
What it means
Thrown in SingleStoreInsertBuilder.values (insert.ts:68) when the normalized values array has length 0. An INSERT with zero value rows is not valid SQL, so Drizzle rejects it at the builder level rather than emitting an incomplete statement.
Source
Thrown at drizzle-orm/src/singlestore-core/query-builders/insert.ts:68
constructor(
private table: TTable,
private session: SingleStoreSession,
private dialect: SingleStoreDialect,
) {}
ignore(): this {
this.shouldIgnore = true;
return this;
}
values(value: SingleStoreInsertValue<TTable>): SingleStoreInsertBase<TTable, TQueryResult, TPreparedQueryHKT>;
values(values: SingleStoreInsertValue<TTable>[]): SingleStoreInsertBase<TTable, TQueryResult, TPreparedQueryHKT>;
values(
values: SingleStoreInsertValue<TTable> | SingleStoreInsertValue<TTable>[],
): SingleStoreInsertBase<TTable, TQueryResult, TPreparedQueryHKT> {
values = Array.isArray(values) ? values : [values];
if (values.length === 0) {
throw new Error('values() must be called with at least one value');
}
const mappedValues = values.map((entry) => {
const result: Record<string, Param | SQL> = {};
const cols = this.table[Table.Symbol.Columns];
for (const colKey of Object.keys(entry)) {
const colValue = entry[colKey as keyof typeof entry];
result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]);
}
return result;
});
return new SingleStoreInsertBase(this.table, mappedValues, this.shouldIgnore, this.session, this.dialect);
}
}
export type SingleStoreInsertWithout<
T extends AnySingleStoreInsert,
TDynamic extends boolean,View on GitHub (pinned to b7862528fd)
Solutions
- Guard the insert: `if (rows.length) await db.insert(t).values(rows);`.
- Default to a no-op or skip when the input array is empty.
- Validate at the API boundary that the payload contains at least one record.
Example fix
// before
await db.insert(users).values(batch);
// after
if (batch.length > 0) {
await db.insert(users).values(batch);
} Defensive patterns
Strategy: validation
Validate before calling
if (Array.isArray(rows) ? rows.length === 0 : false) {
throw new Error('Cannot insert an empty batch');
}
if (rows.length > 0) await db.insert(table).values(rows); Type guard
function hasAtLeastOneValue(v) { return Array.isArray(v) ? v.length > 0 : v != null; } Prevention
- Guard batch inserts with `if (rows.length)`.
- Validate API payloads contain at least one record before inserting.
- Treat empty batches as a no-op, not an error path.
When it happens
Trigger: Calling db.insert(table).values([]) directly; passing a runtime array variable that happens to be empty (e.g. results of a filter that returned nothing); spreading a generated list without a guard.
Common situations: Batch insert paths where upstream filtering produced no rows; UI bulk-save with no changes; ETL step that receives an empty chunk; tests that pass [] as a placeholder.
Related errors
- values() must be called with at least one value
- values() must be called with at least one value
- Insert select error: selected fields are not the same or are
- values() must be called with at least one value
- Insert select error: selected fields are not the same or are
AI-assisted analysis of drizzle-team/drizzle-orm@b7862528fd (2026-08-03).
Data as JSON: /data/errors/2ddee9c318186bf4.json.
Report an issue: GitHub.