windmill-labs/windmill · error
Mixed types in array
Error message
Mixed types in array
What it means
When converting a JSON array argument to a single-typed PostgreSQL array, `map_as_single_type` maps every element through the same converter `f`. If any conversion returns `None`, the elements are of mixed/incompatible types for the target array type, and the collect yields None -> this error. PostgreSQL arrays are homogeneous, so mixed element types cannot be bound as one parameter.
Source
Thrown at backend/windmill-worker/src/pg_executor.rs:1235
fn map_as_single_type<T>(
vec: Option<&Vec<Value>>,
f: impl Fn(&Value) -> Option<T>,
) -> anyhow::Result<Option<Vec<Option<T>>>> {
if let Some(vec) = vec {
Ok(Some(
vec.into_iter()
.map(|v| {
// first option is if the value is of the right type (if none, will stop the collection and throw error)
// second option is if the value is null
// allow nulls in arrays
if matches!(v, Value::Null) {
Some(None)
} else {
f(v).map(Some)
}
})
.collect::<Option<Vec<Option<T>>>>()
.ok_or_else(|| anyhow::anyhow!("Mixed types in array"))?,
))
} else {
Ok(None)
}
}
/// A boxed `ToSql` value paired with the Postgres `Type` that matches its
/// concrete Rust type. Returned by `convert_val` / `convert_vec_val` so the
/// dispatch in `do_postgresql_inner` always asserts the type that the encoder
/// can actually produce — never a parser-derived guess that drifts from the
/// runtime binding.
type ConvertedParam = (Box<dyn ToSql + Sync + Send>, Type);
fn convert_vec_val(
vec: Option<&Vec<Value>>,
arg_t: &String,
) -> windmill_common::error::Result<ConvertedParam> {
match arg_t.as_str() {View on GitHub (pinned to e474e8803c)
Solutions
- Normalize the array in your script before passing it: ensure every element is the same type (e.g. map all to numbers or strings).
- If nulls are intentional, confirm the declared element type allows NULL and elements are otherwise homogeneous.
- Declare the correct arg otyp (e.g. `text[]` vs `int[]`) matching your actual data.
- Flatten nested arrays into one level, or pass JSONB instead of an array type and cast in SQL.
Example fix
// before: mixed types const ids = [1, "2", "3"]; // int[] fails // after const ids = [1, 2, 3]; // or ["1","2","3"] for text[]
Defensive patterns
Strategy: validation
Validate before calling
// validate homogeneity before passing an array arg
function isHomogeneous(arr) {
const kinds = new Set(arr.map(v => v === null ? 'null' : typeof v));
return kinds.size <= 2 && !(kinds.has('object'));
}
// throw if !isHomogeneous(myArray) Type guard
fn all_same_type(v: &[serde_json::Value], f: impl Fn(&serde_json::Value) -> Option<T>) -> bool {
v.iter().all(|x| f(x).is_some())
} Prevention
- Coerce array elements to one type before passing (e.g. .map(Number))
- Match the declared array otyp (int[] vs text[]) to your data
- Use JSONB with an in-SQL cast for genuinely heterogeneous payloads
- Flatten nested arrays before binding
When it happens
Trigger: `convert_vec_val` handling an array arg whose elements don't all fit the resolved element type — e.g. `[1, "two", null-ish object]` against `int[]`, or a heterogeneous JSON array bound to any declared array type.
Common situations: Users passing `[1, '2', 'three']` from JS/Python where strings and numbers mix; JSON input from webhooks with inconsistent element shapes; nested arrays where a flat array type was declared; objects accidentally included in an otherwise numeric array.
Related errors
- Flow notes must be an array
- Missing otyp for pg arg
- Unsupported JSON array type
- result.substring(__RESULT_ERR_PREFIX.length)
- ${scriptPath} declares no S3Object parameter to bind --uploa
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/04b0c1862bcc8efd.
Report an issue: GitHub.