risingwavelabs/risingwave · error
bad result from mysql
Error message
bad result from mysql
What it means
Same contract as the sqlite variant: the MySQL-backed election client's try_campaign expects its campaign upsert statement to return exactly one row (the leader row). An empty result is rejected with 'bad result from mysql', meaning the store failed to return the row that should have just been written.
Solutions
- Confirm the election table exists in the configured database and is InnoDB with proper primary key.
- Check that all meta nodes point to the same MySQL instance/schema (no split-brain across replicas or proxy).
- Inspect MySQL error log and meta logs for lock wait/timeout errors around the campaign time.
- Retry election; if persistent, verify mysql_async driver version compatibility.
Defensive patterns
Strategy: retry
Try / catch
match client.try_campaign(service, lock_id).await {
Err(e) if e.to_string().contains("bad result from mysql") => {
// check connectivity to the same primary instance, then retry
tokio::time::sleep(Duration::from_secs(1)).await;
}
other => other?,
} Prevention
- Point all meta nodes at the same MySQL primary (no split-brain proxies or lagging replicas).
- Use an InnoDB table with a proper primary key for the election table.
- Monitor for lock-wait timeouts on the election table.
When it happens
Trigger: try_campaign on MySqlElectionClient when the campaign query returns zero rows despite executing successfully.
Common situations: MySQL server misconfiguration or replication lag wiping the read-back row; using a non-InnoDB table or unusual isolation level for the election table; connection pool pointing at a different database node between write and read.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/5c05c004bcb8e755.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/src/rpc/election/sql.rs:366
.await?;
let query_result = self
.conn
.query_one(Statement::from_sql_and_values(
DatabaseBackend::MySql,
format!(
r#"SELECT service, id, last_heartbeat FROM {table} WHERE service = ?;"#,
table = Self::election_table_name(),
),
vec![Value::from(service_name)],
))
.await?;
let row = query_result
.map(|query_result| ElectionRow::from_query_result(&query_result, ""))
.transpose()?;
let row = row.ok_or_else(|| anyhow!("bad result from mysql"))?;
Ok(row)
}
async fn leader(&self, service_name: &str) -> MetaResult<Option<ElectionRow>> {
let query_result = self
.conn
.query_one(Statement::from_sql_and_values(
DatabaseBackend::MySql,
format!(
r#"SELECT service, id, last_heartbeat FROM {table} WHERE service = ?;"#,
table = Self::election_table_name()
),
vec![Value::from(service_name)],
))
.await?;
let row = query_resultView on GitHub (pinned to 6469eb736d)