windmill-labs/windmill · error
Failed to parse flow value: {}
Error message
Failed to parse flow value: {} What it means
NewFlow::parse_flow_value deserializes the flow's raw JSON `value` column into the strongly-typed FlowValue struct. If the stored JSON does not conform to the FlowValue schema (missing required fields, wrong types, malformed JSON), the serde error is wrapped and rethrown with this message.
Source
Thrown at backend/windmill-types/src/flows.rs:153
/// Authorization identity to run as, paired with `on_behalf_of_email`. Both move
/// together under the same `preserve_on_behalf_of` gate and must name the same user
/// or group; `None` has it derived from that email rather than left unset.
pub on_behalf_of: Option<String>,
pub preserve_on_behalf_of: Option<bool>,
pub ws_error_handler_muted: Option<bool>,
#[serde(default)]
pub labels: Option<Vec<String>>,
/// Caller-intent flag (set by the CLI / git sync): when true, deploying
/// this flow must NOT delete an existing user draft at the same path.
/// Transient — never persisted.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub skip_draft_deletion: Option<bool>,
}
impl NewFlow {
pub fn parse_flow_value(&self) -> anyhow::Result<FlowValue> {
serde_json::from_str(self.value.get())
.map_err(|e| anyhow::anyhow!("Failed to parse flow value: {}", e))
}
}
/// Body for updating an existing flow. Mirrors `NewFlow`, but `path` is optional: the
/// flow to update is identified by the URL, so the body only needs `path` to rename it.
/// This matches the `EditVariable` / `EditResource` / `EditApp` convention and lets a
/// caller update in place without restating the path.
#[derive(Debug, Deserialize)]
pub struct EditFlow {
#[serde(default)]
pub path: Option<String>,
pub summary: String,
pub description: Option<String>,
#[serde(deserialize_with = "validate_flow_value")]
pub value: Box<RawValue>,
pub schema: Option<Schema>,
pub tag: Option<String>,
pub dedicated_worker: Option<bool>,View on GitHub (pinned to e474e8803c)
Solutions
- Validate the flow JSON against the FlowValue schema before sending; easiest is to export a working flow from the UI and diff against it
- Fix the JSON type errors listed in the wrapped serde message (field names and expected types are named there)
- Add missing required fields (modules, root_module, etc.) or remove unknown/mistyped fields
- If caused by a version upgrade, migrate the stored flow to the current schema
Example fix
// before
{"value": "{\"modules\": []}"}
// after
{"value": "{\"modules\": [], \"root_module\": {\"modules\": [], \"value\": {\"type\": \"branchall\", \"branches\": []}}}"} Defensive patterns
Strategy: validation
Validate before calling
// validate before sending to the flows API
const parsed = JSON.parse(flowValueJson); // throws on malformed JSON
if (!Array.isArray(parsed.modules) || parsed.modules.length === 0)
throw new Error("flow value must have a non-empty 'modules' array");
if (!parsed.root_module) throw new Error("flow value must have 'root_module'"); Type guard
function isFlowValue(v: unknown): v is { modules: unknown[]; root_module: unknown } {
return typeof v === "object" && v !== null && "modules" in v && "root_module" in v;
} Try / catch
try {
const flow = await wm.flows.create({ path, value });
} catch (e) {
if (String(e.message).startsWith("Failed to parse flow value")) {
console.error("Flow schema mismatch:", e.message); // serde detail is embedded
} else throw e;
} Prevention
- Export a known-good flow from the UI and use its JSON as a template
- Validate flow JSON against the FlowValue schema in CI before deploy
- After Windmill upgrades, re-export flows to pick up schema changes
When it happens
Trigger: Creating/updating a flow (POST /api/w/{workspace}/flows/create or /flows/get/{path}) where the `value` field is invalid JSON or doesn't match FlowValue, e.g. missing 'modules' or 'root_module'. Also hit via guard_flow_from_debounce_data when handling debounce payloads.
Common situations: Hand-crafting flow JSON in API scripts, older flow definitions from previous Windmill versions that lack newly-required fields, truncated JSON, or programmatic deploys that serialize the wrong object shape.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- {}
- Completed jobs file must contain an array of jobs
- Queued jobs file must contain an array of jobs
- Invalid JSON for ${field}: ${errorMessage}
- Invalid JSON after replacement: ${message}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/db930c9319cfd880.
Report an issue: GitHub.