tursodatabase/turso · error

query was interrupted

Error message

query was interrupted

What it means

The benchmark's execute loop steps a prepared statement to completion. A StepResult::Interrupt means the database was interrupted (interrupt flag set) while the query was running, so the benchmark bails out instead of returning partial row counts.

Source

Thrown at perf/join-benchmark/main.rs:172

                .with_context(|| format!("read query file {}", path.display()))?,
        });
    }
    Ok(queries)
}

fn set_timeout(statement: &mut turso_core::Statement, timeout_seconds: u64) {
    let timeout = (timeout_seconds != 0).then(|| Duration::from_secs(timeout_seconds));
    statement.set_query_timeout_override(Some(timeout));
}

fn execute(database: &Database, statement: &mut turso_core::Statement) -> Result<u64> {
    let mut result_rows = 0_u64;
    loop {
        match statement.step()? {
            StepResult::Row => result_rows = result_rows.saturating_add(1),
            StepResult::IO | StepResult::Yield | StepResult::Sleep { .. } => database.io.step()?,
            StepResult::Done => return Ok(result_rows),
            StepResult::Interrupt => bail!("query was interrupted"),
            StepResult::Busy => bail!("database was busy"),
        }
    }
}

fn print_plan(connection: &Arc<turso_core::Connection>, query: &Query) -> Result<()> {
    let sql = format!("EXPLAIN QUERY PLAN FORMAT=JSON {}", query.sql);
    let rows = connection.prepare(sql)?.run_collect_rows()?;
    let Some(Value::Text(plan)) = rows.first().and_then(|row| row.first()) else {
        bail!("query {} did not return a JSON plan", query.name);
    };
    let plan: JsonValue = serde_json::from_str(plan.as_str())?;
    println!("{}", json!({"query": query.name, "plan": plan}));
    Ok(())
}

View on GitHub (pinned to 492c4a71cd)

Solutions

  1. Increase the benchmark time budget/timeout so the query finishes before the interrupt fires.
  2. Optimize or disable the offending query (check indexes/join order) to make it complete within the limit.
  3. Check what sets the interrupt flag (signal handler, deadline task) and whether it fires prematurely.
  4. Retry the run; if it's consistently interrupted, profile the query for a pathological plan.

Example fix

// before
let deadline = Instant::now() + Duration::from_secs(5);
// after
let deadline = Instant::now() + Duration::from_secs(60);
Defensive patterns

Strategy: try-catch

Try / catch

match execute(&database, &mut statement) {
    Err(e) if e.to_string().contains("query was interrupted") => {
        eprintln!("query exceeded time budget: {e}");
        // raise budget or skip query
    }
    other => other?,
}

Prevention

When it happens

Trigger: statement.step() returns StepResult::Interrupt during a long join query — the database/connection interrupt flag was set, e.g. by a deadline/timeout mechanism or an external interrupt request.

Common situations: Query exceeding an imposed time limit with interrupt wired to a timer; Ctrl-C handling that flags the database; long-running join hitting a harness timeout.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of tursodatabase/turso@492c4a71cd (2026-09-13). Data as JSON: /api/errors/745ebdc5f8615fdb. Report an issue: GitHub.