clockworklabs/SpacetimeDB · error

heterogeneous array

Error message

heterogeneous array

What it means

Panic in SpacetimeDB's serde integration for `AlgebraicValue`. SatS arrays are strictly homogeneous; when a type is serialized through `SerializeArrayValue`, every element must serialize to the same primitive kind. `ArrayValueBuilder::push` enforces this and `expect("heterogeneous array")` fires when element N has a different value type than elements 0..N-1.

Source

Thrown at crates/sats/src/algebraic_value/ser.rs:248

}

/// Continuation for serializing an array.
pub struct SerializeArrayValue {
    /// For efficiency, the first time `serialize_element` is done,
    /// this is used to allocate with capacity.
    len: Option<usize>,
    /// The array being built.
    array: ArrayValueBuilder,
}

impl ser::SerializeArray for SerializeArrayValue {
    type Ok = AlgebraicValue;
    type Error = <ValueSerializer as ser::Serializer>::Error;

    fn serialize_element<T: ser::Serialize + ?Sized>(&mut self, elem: &T) -> Result<(), Self::Error> {
        self.array
            .push(value_serialize(elem), self.len.take())
            .expect("heterogeneous array");
        Ok(())
    }

    fn end(self) -> Result<Self::Ok, Self::Error> {
        Ok(ArrayValue::from(self.array).into())
    }
}

/// A builder for [`ArrayValue`]s
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
enum ArrayValueBuilder {
    /// An array of [`SumValue`](crate::SumValue)s.
    Sum(Vec<crate::SumValue>),
    /// An array of [`ProductValue`](crate::ProductValue)s.
    Product(Vec<crate::ProductValue>),
    /// An array of [`bool`]s.
    Bool(Vec<bool>),
    /// An array of [`i8`]s.

View on GitHub (pinned to 6dee26c6ef)

Solutions

  1. Normalize the data before serialization: map every element to one type (e.g. stringify scalars, or wrap in a sum type with uniform variants).
  2. Define a proper SatS schema element type (product or sum type) so all elements serialize identically, instead of relying on dynamic/any serialization.
  3. If consuming JSON, pre-validate the array with a check that all elements share one JSON kind before converting to `AlgebraicValue`.
  4. For custom Serialize impls, ensure element serialization is uniform — heterogeneous logic belongs in a sum type with named variants.

Example fix

// before: heterogeneous JSON array -> panics
let v: AlgebraicValue = value_serialize(&serde_json::json!([1, "two", true]));

// after: normalize all elements to one shape first
let v: AlgebraicValue = value_serialize(&vec!["1", "two", "true"]); // homogeneous strings
Defensive patterns

Strategy: type-guard

Validate before calling

// Before serializing dynamic data, assert all elements share one value kind
fn homogeneous(vals: &[serde_json::Value]) -> bool {
    match vals.split_first() {
        Some((f, rest)) => rest.iter().all(|v| std::mem::discriminant(v) == std::mem::discriminant(f)),
        None => true,
    }
}

Type guard

fn uniform_array(v: &serde_json::Value) -> Option<&Vec<serde_json::Value>> {
    v.as_array().filter(|a| homogeneous(a))
}

Try / catch

let r = std::panic::catch_unwind(AssertUnwindSafe(|| value_serialize(&data)));
match r { Ok(v) => v, Err(_) => return Err(SerializationError::heterogeneous_array) }

Prevention

When it happens

Trigger: Serializing a Rust sequence (Vec/array/struct with `deserialize_with`-style element visitors, or `serde_json::Value`-like dynamic data) into an `AlgebraicValue` where elements serialize to different kinds — e.g. first element serializes as an integer and the second as a string or a sum variant. Common with `serialize_any`-style serializers, enums with differing variant payloads, or serde_json `Value::Array` mixing number/string/bool.

Common situations: Storing JSON-ish dynamic data (`serde_json::Value`) in a SatS `array value` column; custom `Serialize` impls that emit different shapes per element; converting between formats where JSON allows heterogeneous arrays but SatS does not; RPC/subscription payloads round-tripping untyped JSON.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20). Data as JSON: /api/errors/e7d26342736a2dfd. Report an issue: GitHub.