windmill-labs/windmill · error
`required` field should be an array of strings
Error message
`required` field should be an array of strings
What it means
The top-level `required` key exists but is not a JSON array. from_schema calls as_array on it and rejects any non-array value. Additionally, though the message says 'array of strings', the element check surfaces separately as 'required field key is not a string' (error 946).
Source
Thrown at backend/windmill-common/src/schema.rs:528
}
pub fn from_schema(schema: &str) -> Result<Self, Error> {
let schema: Value = serde_json::from_str(schema)?;
if let Some(draft_version) = schema.get("$schema") {
match draft_version.as_str() {
Some("https://json-schema.org/draft/2020-12/schema") => (),
_ => return Err(anyhow!("Supplied schema draft version is unsuported").into()),
}
} else {
return Err(anyhow!("No draft version supplied").into());
}
let required: Vec<String> = schema
.get("required")
.ok_or(anyhow!("Missing `required` field on schema"))?
.as_array()
.ok_or(anyhow!("`required` field should be an array of strings"))?
.into_iter()
.map(|v| {
v.as_str()
.map(|s| s.to_string())
.ok_or(anyhow!("required field key is not a string"))
})
.collect::<Result<Vec<String>, anyhow::Error>>()?;
let properties = schema
.get("properties")
.ok_or(anyhow!("Missing `properties` field on schema"))?
.as_object()
.ok_or(anyhow!("`properties` field should be an object"))?;
let mut rules = vec![];
for (key, val) in properties {
rules.push((View on GitHub (pinned to e474e8803c)
Solutions
- Change `required` to a JSON array of property-name strings, e.g. "required": ["a","b"].
- If migrating from OpenAPI, remove per-property "required": true and list those names in the top-level array instead.
Example fix
// before
{"properties": {"a": {"type": "string", "required": true}}}
// after
{"properties": {"a": {"type": "string"}}, "required": ["a"]} Defensive patterns
Strategy: type-guard
Validate before calling
fn validate_required_is_array(schema: &serde_json::Value) -> Result<(), String> {
match schema.get("required") {
Some(r) if r.is_array() => Ok(()),
Some(_) => Err("`required` must be a JSON array of strings".into()),
None => Err("missing `required`".into()),
}
} Type guard
fn required_is_string_array(schema: &serde_json::Value) -> bool {
schema.get("required")
.and_then(|r| r.as_array())
.map(|a| a.iter().all(|v| v.is_string()))
.unwrap_or(false)
} Try / catch
match Schema::from_schema(&schema_str) {
Ok(s) => s,
Err(e) if e.to_string().contains("required` field should be an array") => {
eprintln!("convert `required` to a JSON array of property names");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Remember JSON Schema `required` is an array at the object level, not per-property flags
- When converting from OpenAPI, gather per-property required:true names into one array
When it happens
Trigger: Calling Schema::from_schema with "required": "a" (a string), "required": {"a": true}, or "required": true — any non-array JSON value at the top-level `required` key.
Common situations: Confusing JSON Schema `required` (array) with OpenAPI-style per-property required: true, or schemas authored by tools expecting draft semantics where required lives inside each property.
Related errors
- required field key is not a string
- `properties` field should be an object
- Unsupported value for type field, expected string or string
- enum variants are not in an array
- Supplied schema draft version is unsuported
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/eef212e5f183a8ab.
Report an issue: GitHub.