t8y2/dbx · error

TDengine query returned no rows

Error message

TDengine query returned no rows

What it means

query_scalar_string executes a statement expected to return exactly a scalar (used by connect/validate_connection for version/health checks). When the server returns zero rows (fetch_raw_block yields None), the driver errors because there is no scalar to return. Note: a block with 0 rows or 0 columns is skipped and the loop keeps polling until exhaustion.

Source

Thrown at agents/drivers/tdengine/src/driver.rs:770

        execution_time_ms: 0,
        truncated: false,
        session_id: None,
        has_more: false,
    })
}

async fn query_scalar_string(
    connection: &Taos,
    sql: &str,
    token: &CancellationToken,
    timeout_secs: u64,
) -> Result<String> {
    let mut result = cancellable(token, timeout_secs, connection.query(sql)).await?;
    let timezone = result.timezone();
    loop {
        let block = cancellable(token, timeout_secs, poll_fn(|context| result.fetch_raw_block(context))).await?;
        let Some(block) = block else {
            bail!("TDengine query returned no rows");
        };
        if block.nrows() == 0 || block.ncols() == 0 {
            continue;
        }
        let value = block.get_ref(0, 0).ok_or_else(|| anyhow!("TDengine query returned an empty value"))?;
        return match borrowed_value_to_json(value, preferred_timezone(timezone, block.timezone(), None)) {
            Value::String(value) => Ok(value),
            value => Ok(value.to_string()),
        };
    }
}

fn preferred_timezone(
    query_timezone: Option<Tz>,
    block_timezone: Option<Tz>,
    session_timezone: Option<Tz>,
) -> Option<Tz> {
    query_timezone.or(block_timezone).or(session_timezone)

View on GitHub (pinned to c0390bff16)

Solutions

  1. Fix the scalar query to always return one row (e.g. use aggregates: SELECT COUNT(*) FROM ... or SELECT FIRST(value) ...)
  2. Use execute_query/query_rows instead if zero rows is an expected outcome
  3. Guard the caller: treat 'no rows' as a distinct result rather than routing it through the scalar helper

Example fix

// before
let v = query_scalar_string(conn, "SELECT value FROM config WHERE id=42", ...).await?;
// after
let v = query_scalar_string(conn, "SELECT COALESCE(MAX(value), 'default') FROM config WHERE id=42", ...).await?;
Defensive patterns

Strategy: fallback

Validate before calling

// prefer queries guaranteed to return one row
let sql = "SELECT COALESCE(MAX(value), '') FROM t WHERE id=42";

Try / catch

match query_scalar_string(conn, sql, &token, timeout).await {
    Err(e) if e.to_string().contains("no rows") => Ok(String::new()), // default
    other => other,
}

Prevention

When it happens

Trigger: Running a scalar query that matches no rows — e.g. SELECT value FROM meta WHERE key='x' with no such row, or an empty table — via query_scalar_string during connect or validate_connection.

Common situations: Health-check queries against a fresh/empty database, mistyped metadata keys, or a database/user without the queried object so the query legitimately returns no rows.

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 t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/498e6e046d2ce47b. Report an issue: GitHub.