beekeeper-studio/beekeeper-studio · warning

Query not ready to be canceled

Error message

Query not ready to be canceled

What it means

In SqliteClient's query execution, a dedicated worker 'queryConnection' is opened asynchronously while the cancel() closure is returned immediately. cancel() throws 'Query not ready to be canceled' if the closure-scoped queryConnection variable is still null — i.e. cancellation was requested before the worker connection finished opening (or it was never assigned). It signals the query cannot be canceled at that moment, not that the query itself failed.

Source

Thrown at apps/studio/src/lib/db/clients/sqlite.ts:315

          if (err.code === sqliteErrors.CANCELED) {
            err.sqlectronError = 'CANCELED_BY_USER';
          }

          if (err.message?.startsWith('no such column')) {
            const nuError = new ClientError(`${err.message} - Check that you only use double quotes (") for identifiers, not strings`, "https://docs.beekeeperstudio.io/support/troubleshooting/#no-such-column-x");
            throw nuError
          }

          throw err;
        } finally {
          if (queryConnection !== this._rawConnection) {
            queryConnection.close();
          }
        }
      }).bind(this),
      async cancel() {
        if (!queryConnection) {
          throw new Error('Query not ready to be canceled');
        }
      }
    }
  }

  async executeQuery(queryText: string, options: any = {}): Promise<NgQueryResult[]> {
    const arrayMode: boolean = options.arrayMode;
    const result = await this.driverExecuteMultiple(queryText, options);
    const commands = this.identifyCommands(queryText)

    return (result || []).map(({ rows: data, columns, statement, changes }, i) => {
      // Fallback in case the identifier could not reconize the command
      const text = commands[i]?.text;
      const isSelect = Array.isArray(data);
      let rows: any[];
      let fields: any[];

      if (isSelect && arrayMode) {

View on GitHub (pinned to 4e3e03e322)

Solutions

  1. Delay cancellation slightly and retry until queryConnection is assigned (poll or wait a tick).
  2. Treat this error as benign: check whether the query already completed before showing a failure.
  3. Serialize cancellation: disable the cancel button until the query reports it is actually running.
  4. Track the query's lifecycle and make cancel() a no-op when the query is already finished or the connection closed.

Example fix

// before
await handle.cancel();
// after
try {
  await handle.cancel();
} catch (err) {
  if (!/not ready to be canceled/i.test(err.message)) throw err; // query likely already done
}
Defensive patterns

Strategy: retry

Validate before calling

// only cancel once the query reports it is running
if (!queryHandle.isRunning || !queryHandle.isRunning()) return;

Type guard

function isCancelable(handle: QueryHandle): boolean {
  return typeof handle.cancel === 'function' && handle.isRunning?.() === true;
}

Try / catch

const cancelWithRetry = async (handle, retries = 3) => {
  for (let i = 0; i < retries; i++) {
    try { return await handle.cancel(); }
    catch (err) {
      if (!/not ready to be canceled/i.test(err.message) || i === retries - 1) {
        if (/not ready to be canceled/i.test(err.message)) return; // query likely done
        throw err;
      }
      await new Promise(r => setTimeout(r, 100));
    }
  }
};

Prevention

When it happens

Trigger: Calling cancel() on the query handle immediately after starting a query, before the SQLite worker connection has opened; canceling after the connection already closed; racing a cancel against a very fast query that finished and tore down the connection.

Common situations: UIs with a cancel button that can be clicked during the brief connection-setup window; automated tests canceling instantly; user cancels a long query twice and the second cancel lands after teardown.

Related errors


AI-assisted analysis of beekeeper-studio/beekeeper-studio@4e3e03e322 (2026-08-31). Data as JSON: /api/errors/0b6b4907050c68a2. Report an issue: GitHub.