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

  1. Set CommandText to non-empty SQL before executing the batch
  2. Guard: skip adding the batch command when string.IsNullOrWhiteSpace(sql)
  3. 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

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


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-09-06). Data as JSON: /api/errors/e2a93b61c1e0f4b5. Report an issue: GitHub.