databendlabs/databend · error

failed to build jsonb array

Error message

failed to build jsonb array

What it means

cast_scalar_to_variant converts an Array scalar into a jsonb value; it collects per-element variants and calls OwnedJsonb::build_array, expecting array construction to succeed. The panic fires when jsonb's build_array returns an error — typically because the accumulated document exceeds jsonb size limits (depth/size constraints of the jsonb format), or an internal jsonb encoding failure.

Solutions

  1. Reduce array size/nesting before casting to VARIANT.
  2. Replace expect with error propagation returning ErrorCode (e.g. jsonb build failure) to fail the query gracefully.
  3. Check jsonb crate limits and enforce an application-level limit on array length in cast functions.

Example fix

// before
let owned_jsonb = OwnedJsonb::build_array(items.iter().map(RawJsonb::new))
    .expect("failed to build jsonb array");
// after
let owned_jsonb = OwnedJsonb::build_array(items.iter().map(RawJsonb::new))
    .map_err(|e| ErrorCode::BadArguments(format!("failed to build jsonb array: {e}")))?;
Defensive patterns

Strategy: fallback

Validate before calling

if items.len() > MAX_JSONB_ARRAY_ITEMS {
    return Err(ErrorCode::BadArguments("array too large to cast to VARIANT"));
}

Try / catch

// Catch panics around cast if it cannot be changed:
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    cast_scalar_to_variant(scalar, tz, &mut buf, table_data_type);
}));
if result.is_err() { /* fail query gracefully or emit NULL variant */ }

Prevention

When it happens

Trigger: Casting an ARRAY scalar with a very large number of elements or very large encoded items such that the built jsonb exceeds internal size limits; recursive cast_scalar_to_variant → cast_scalars_to_variants on deeply nested arrays.

Common situations: Queries constructing huge arrays via ARRAY(...) or array_agg then casting to VARIANT/JSON; deeply nested array literals blowing jsonb depth limits during expression evaluation.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/f55796e7e6d90638. Report an issue: GitHub.

Appendix: source

Thrown at src/query/expression/src/types/variant.rs:308

        }),
        ScalarRef::Date(d) => jsonb::Value::Date(jsonb::Date { value: d }),
        ScalarRef::Interval(i) => {
            let interval = jsonb::Interval {
                months: i.months(),
                days: i.days(),
                micros: i.microseconds(),
            };
            jsonb::Value::Interval(interval)
        }
        ScalarRef::Array(col) => {
            let typ = if let Some(TableDataType::Array(typ)) = table_data_type {
                Some(typ.remove_nullable())
            } else {
                None
            };
            let items = cast_scalars_to_variants(col.iter(), tz, typ.as_ref());
            let owned_jsonb = OwnedJsonb::build_array(items.iter().map(RawJsonb::new))
                .expect("failed to build jsonb array");
            buf.extend_from_slice(owned_jsonb.as_ref());
            return;
        }
        ScalarRef::Map(col) => {
            let typ = if let Some(TableDataType::Map(typ)) = table_data_type {
                Some(typ.remove_nullable())
            } else {
                None
            };

            let kv_col = KvPair::<AnyType, AnyType>::try_downcast_column(&col).unwrap();
            let mut kvs = BTreeMap::new();
            for (k, v) in kv_col.iter() {
                let key = match k {
                    ScalarRef::String(v) => v.to_string(),
                    ScalarRef::Number(v) => v.to_string(),
                    ScalarRef::Decimal(v) => v.to_string(),
                    ScalarRef::Boolean(v) => v.to_string(),

View on GitHub (pinned to 288d84d76e)