risingwavelabs/risingwave · error · ExprError

More than one row returned by {0} used as an expression

Error message

More than one row returned by {0} used as an expression

What it means

ExprError::MaxOneRow(&'static str) is thrown when a scalar subquery (or similar row-yielding expression) returns more than one row. The message interpolates what construct ('{0}') was used as an expression, mirroring Postgres's 'more than one row returned by a subquery used as an expression'. A scalar context can only consume a single row.

Source

Thrown at src/expr/core/src/error.rs:88

    #[error("Parse error: {0}")]
    // TODO(error-handling): should prefer use error types than strings.
    Parse(Box<str>),

    #[error("Invalid parameter {name}: {reason}")]
    // TODO(error-handling): should prefer use error types than strings.
    InvalidParam {
        name: &'static str,
        reason: Box<str>,
    },

    #[error("Array error: {0}")]
    Array(
        #[from]
        #[backtrace]
        ArrayError,
    ),

    #[error("More than one row returned by {0} used as an expression")]
    MaxOneRow(&'static str),

    /// TODO: deprecate in favor of `Function`
    #[error(transparent)]
    Internal(
        #[from]
        #[backtrace]
        anyhow::Error,
    ),

    #[error("not a constant")]
    NotConstant,

    #[error("Context {0} not found")]
    Context(&'static str),

    #[error("field name must not be null")]
    FieldNameNull,

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Add `LIMIT 1` if any single row is acceptable.
  2. Add `DISTINCT` when duplicates are spurious.
  3. Tighten the subquery's WHERE clause (or add a unique constraint) so it provably returns at most one row.

Example fix

// before
SELECT * FROM a WHERE id = (SELECT a_id FROM b WHERE flag = true);
// after
SELECT * FROM a WHERE id = (SELECT a_id FROM b WHERE flag = true LIMIT 1);
Defensive patterns

Strategy: validation

Validate before calling

-- ensure scalar subquery yields at most one row
SELECT * FROM a WHERE id = (SELECT DISTINCT a_id FROM b WHERE flag = true LIMIT 1);

Try / catch

// Postgres-compatible error; catch and rewrite with LIMIT at retry
if err.to_string().contains("More than one row returned") {
    return run(query_with_limit_1);
}

Prevention

When it happens

Trigger: A scalar subquery on the right side of `=`, in a SELECT list, or in a SET clause produces 2+ rows, e.g. `SELECT x = (SELECT id FROM t WHERE k = 1)` where the WHERE clause matches multiple rows.

Common situations: Subqueries written against a uniqueness assumption that no longer holds after data changes, missing DISTINCT/LIMIT, join fan-out in upstream tables making lookups non-unique.

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/8d3edf6308fd8b09. Report an issue: GitHub.