tursodatabase/turso · error · DatabaseError

SQL execution failed

Error message

SQL execution failed

What it means

DatabaseError thrown while consuming the cursor stream of Session.execute() — the path behind Connection/Transaction run/get/all and Statement execution — when the server sends a step_error or fatal error entry. The server's message is preferred; the literal 'SQL execution failed' is the fallback for entries that carry no error.message.

Source

Thrown at serverless/javascript/src/session.ts:385

          if (entry.row) {
            const decodedRow = entry.row.map(value => decodeValue(value, safeIntegers));
            const rowObject = this.createRowObject(decodedRow, columns);
            rows.push(rowObject);
          }
          break;
        case 'step_end':
          if (entry.affected_row_count !== undefined) {
            rowsAffected = entry.affected_row_count;
          }
          if (entry.last_insert_rowid !== undefined && entry.last_insert_rowid !== null) {
            lastInsertRowid = typeof entry.last_insert_rowid === 'number'
              ? entry.last_insert_rowid
              : parseInt(entry.last_insert_rowid, 10);
          }
          break;
        case 'step_error':
        case 'error':
          throw new DatabaseError(entry.error?.message || 'SQL execution failed', entry.error?.code);
      }
    }

    return {
      columns,
      columnTypes,
      rows,
      rowsAffected,
      lastInsertRowid
    };
  }

  /**
   * Create a row object with both array and named property access.
   * 
   * @param values - Array of column values
   * @param columns - Array of column names
   * @returns Row object with dual access patterns

View on GitHub (pinned to bad083fafb)

Solutions

  1. Read the server message and DatabaseError.code (e.g. SQLITE_CONSTRAINT_UNIQUE) — they identify the failing statement and reason
  2. Fix the data or schema the message points to (ON CONFLICT clauses, migrations, validated input)
  3. If only the fallback text appears, capture the raw response via a logging proxy and report the server issue

Example fix

// before
await db.run("INSERT INTO users(id) VALUES (?)", 1); // duplicate id -> step_error

// after
await db.run("INSERT INTO users(id) VALUES (?) ON CONFLICT(id) DO NOTHING", 1);
Defensive patterns

Strategy: try-catch

Type guard

const isDatabaseError = (e: unknown): e is Error & { code?: string } =>
  e instanceof Error && e.name === "DatabaseError";

Try / catch

try {
  await db.run(sql, ...args);
} catch (e) {
  const code = (e as { code?: string })?.code;
  if (code === "SQLITE_CONSTRAINT_UNIQUE") {
    // duplicate key: upsert or skip
  } else if (code === "SQLITE_BUSY") {
    // write contention: back off and retry
  } else throw e;
}

Prevention

When it happens

Trigger: Runtime SQL failures surfacing from db.run()/db.get()/db.all() or tx equivalents: UNIQUE/NOT NULL constraint violations, 'no such table/column', SQLITE_BUSY write contention; malformed message-less error entries from a buggy server triggering the fallback text.

Common situations: INSERTs violating constraints with unvalidated data; referencing tables that don't exist in the deployed database; concurrent writers hitting lock timeouts; server bugs emitting errors without messages.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/ee2367089bd4d23d. Report an issue: GitHub.