windmill-labs/windmill · error
required field key is not a string
Error message
required field key is not a string
What it means
Raised by from_schema when an entry inside the schema's `required` array is not a string. Each entry must name a property; non-string entries would compile into unusable validation rules, so the schema is rejected during parsing.
Source
Thrown at backend/windmill-common/src/schema.rs:533
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((
key.clone(),
SchemaValidationRule::from_value(val)
.map_err(|e| anyhow!("Problem making rule for {key}: {e}"))?,
));
}View on GitHub (pinned to e474e8803c)
Solutions
- Make every entry of `required` a plain string naming a property, e.g. "required": ["a","b"].
- Fix the generating code to serialize property names (to_string/name) instead of raw objects or numbers.
Example fix
// before
"required": [{"name": "a"}, 2]
// after
"required": ["a"] Defensive patterns
Strategy: type-guard
Validate before calling
fn validate_required_elements(schema: &serde_json::Value) -> Result<(), String> {
let arr = schema.get("required").and_then(|r| r.as_array())
.ok_or("required missing or not an array")?;
for (i, v) in arr.iter().enumerate() {
if !v.is_string() {
return Err(format!("required[{i}] must be a string, got {v}"));
}
}
Ok(())
} Type guard
fn all_required_strings(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 key is not a string") => {
eprintln!("every `required` entry must be a plain property-name string");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Build required arrays with map(name) in generators so entries are always strings
- Validate array homogeneity before passing the schema
When it happens
Trigger: Calling Schema::from_schema with "required": [1, "a"], "required": [null], or "required": [{"name":"a"}] — at least one element is not a JSON string.
Common situations: Programmatic schema construction where numbers/objects were pushed into the required list, JSON5/JS arrays with mixed types, and schemas copied from formats where required entries carry extra structure.
Related errors
- `required` field should be an array of strings
- `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/f187cc18a2a7ecd1.
Report an issue: GitHub.