tursodatabase/turso · error · InvalidOperationException
Batch command text must contain a SQL statement.
Error message
Batch command text must contain a SQL statement.
What it means
Before executing, BuildBatch parses each batch command's CommandText with ManagedSqliteStatementParser. If parsing yields zero statements (empty or whitespace/comment-only text), an InvalidOperationException is thrown because a batch entry must contain at least one SQL statement.
Source
Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteBatch.cs:303
{
Timeout = Timeout,
Transaction = _transaction?.ManagedTransaction,
};
var statements = new List<ManagedSqliteStatement>();
var managedCommands = new List<global::Turso.TursoBatchCommand>();
var mappings = new List<BatchCommandMapping>(_batchCommands.Count);
try
{
foreach (var batchCommand in _batchCommands.Items)
{
using var command = new SqliteCommand(batchCommand.CommandText, connection, _transaction);
foreach (SqliteParameter parameter in batchCommand.Parameters)
command.Parameters.Add(parameter);
command.ValidateManagedParameterValues();
var commandStatements = ManagedSqliteStatementParser.Parse(batchCommand.CommandText);
if (commandStatements.Count == 0)
throw new InvalidOperationException("Batch command text must contain a SQL statement.");
if (commandStatements.Any(static statement => statement.IsTransactionControl))
{
throw new InvalidOperationException(
"Transaction-control SQL is not supported in a SqliteBatch. "
+ "Use SqliteConnection.BeginTransaction and SqliteTransaction instead.");
}
if (connection.IsReadOnly
&& commandStatements.Any(SqliteCommand.IsWriteStatement))
{
throw new SqliteException(
Properties.Resources.SqliteNativeError(8, "attempt to write a readonly database"),
8);
}
var firstManagedIndex = managedCommands.Count;
foreach (var statement in commandStatements)
{
string sql;View on GitHub (pinned to 6c72522679)
Solutions
- Set CommandText to non-empty SQL before executing the batch
- Guard: skip adding the batch command when string.IsNullOrWhiteSpace(sql)
- Trim/validate all batch command texts during construction
Example fix
// before
batch.Commands.Add(new SqliteBatchCommand { CommandText = maybeEmptySql });
await batch.ExecuteReaderAsync();
// after
if (!string.IsNullOrWhiteSpace(maybeEmptySql))
batch.Commands.Add(new SqliteBatchCommand { CommandText = maybeEmptySql }); Defensive patterns
Strategy: validation
Validate before calling
if (string.IsNullOrWhiteSpace(cmd.CommandText))
throw new InvalidOperationException("Batch command text is empty"); Type guard
static bool HasSql(SqliteBatchCommand c) => !string.IsNullOrWhiteSpace(c.CommandText);
Try / catch
try { await batch.ExecuteReaderAsync(); }
catch (InvalidOperationException ex) when (ex.Message.Contains("must contain a SQL statement")) { /* skip/skip-empty command */ } Prevention
- Validate all CommandTexts when building the batch
- Never add commands with template placeholders that may resolve to empty
- Trim and assert non-empty SQL in your data-access helpers
When it happens
Trigger: Adding a SqliteBatch command whose CommandText is null, empty, whitespace, or only comments (e.g. "-- done"), then calling ExecuteReader/ExecuteBatch.
Common situations: Building command text dynamically from templates where a variable evaluates to empty string; conditional code that skips filling in SQL; trailing comment-only cleanup text.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Turso batch execution is currently supported only for remote
- SQL command cannot be null
- TursoBatchCommand only supports CommandType.Text.
- Batch command must be a TursoBatchCommand.
- Expected first argument to be an array of statements
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-09-06).
Data as JSON: /api/errors/e2a93b61c1e0f4b5.
Report an issue: GitHub.