windmill-labs/windmill · critical
Unable to deserialize group names
Error message
Unable to deserialize group names
What it means
In Windmill's flow execution, an approval/suspend step can require specific user groups. When the requirement is provided as a static input transform, the worker parses its raw JSON string into Vec<String>. If the string is not valid JSON or not an array of strings, serde_json fails and .expect panics the flow job with "Unable to deserialize group names".
Source
Thrown at backend/windmill-worker/src/worker_flow.rs:3465
// Persist approval user groups conditions, if any. Requires runnning the InputTransform
let required_events = suspend.required_events.unwrap() as u16;
let user_auth_required = suspend.user_auth_required.unwrap_or(false);
let self_approval_disabled = suspend.self_approval_disabled.unwrap_or(false);
// self_approval_disabled must be persisted even without user_auth_required, otherwise
// the resume boundary sees no approval_conditions and the restriction is silently
// dropped. user_groups_required only applies together with user_auth_required.
if user_auth_required || self_approval_disabled {
let user_groups_required: Vec<String>;
if !user_auth_required {
user_groups_required = Vec::new();
} else if let Some(user_groups_required_as_input_transform) =
suspend.user_groups_required
{
match user_groups_required_as_input_transform {
InputTransform::Static { value } => {
user_groups_required = serde_json::from_str::<Vec<String>>(value.get())
.expect("Unable to deserialize group names");
}
InputTransform::Javascript { expr } => {
let mut context = HashMap::with_capacity(2);
context.insert("result".to_string(), arc_last_job_result.clone());
context
.insert("previous_result".to_string(), arc_last_job_result.clone());
let eval_result = serde_json::from_str::<Vec<String>>(
eval_timeout(
expr.to_string(),
context,
Some(arc_flow_job_args.clone()),
flow_env,
None,
None,
None
)
.warn_after_seconds(3)View on GitHub (pinned to e474e8803c)
Solutions
- Fix the suspend step's user_groups_required static value to be a valid JSON array of strings, e.g. ["admins","devs"]
- Re-deploy the corrected flow (UI editor, wmill flow push, or SDK)
- If the value must be dynamic, switch the input transform to a JavaScript/AI transform that evaluates to a string array
Example fix
// before (flow definition)
"user_groups_required": { "type": "static", "value": "admins" }
// after
"user_groups_required": { "type": "static", "value": "[\"admins\"]" } Defensive patterns
Strategy: validation
Validate before calling
let groups: Option<Vec<String>> = serde_json::from_str(value.get()).ok();
if groups.is_none() {
eprintln!("user_groups_required static value is not a JSON array of strings: {}", value.get());
} Type guard
fn is_string_array(v: &serde_json::Value) -> bool {
v.as_array().map_or(false, |a| a.iter().all(|x| x.is_string()))
} Try / catch
match serde_json::from_str::<Vec<String>>(value.get()) {
Ok(g) => user_groups_required = g,
Err(e) => return Err(Error::ExecutionErr(format!("Invalid user_groups_required JSON: {e}"))),
} Prevention
- Always author static values as JSON arrays of strings, e.g. ["admins"]
- Validate flow definitions on deploy with a JSON-schema check on suspend settings
- Prefer the UI editor over hand-editing flow YAML/JSON
When it happens
Trigger: A flow suspend step's 'user_groups_required' input transform is set to InputTransform::Static whose value string is not valid JSON (e.g. a bare string, single-quoted JSON, an object, or an array of non-strings).
Common situations: Hand-editing a flow definition YAML/JSON and writing the group list as 'admins, devs' instead of ["admins","devs"]; exporting/importing flows between workspaces with a malformed static value; programmatic flow deploy via SDK with a wrongly-typed value.
Related errors
- Invalid AI agent provider configuration: ${errors.join('\n')
- Cannot convert default value to json value: {unparsed} err
- Failed to parse flow value: {}
- {}
- ${existingName} couldn't be auto-edited (it may contain comm
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/412d6f95aaadee55.
Report an issue: GitHub.