{"record":{"id":"db930c9319cfd880","repo":"windmill-labs/windmill","slug":"failed-to-parse-flow-value","errorCode":null,"errorMessage":"Failed to parse flow value: {}","messagePattern":"Failed to parse flow value: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-types/src/flows.rs","lineNumber":153,"sourceCode":"    /// Authorization identity to run as, paired with `on_behalf_of_email`. Both move\n    /// together under the same `preserve_on_behalf_of` gate and must name the same user\n    /// or group; `None` has it derived from that email rather than left unset.\n    pub on_behalf_of: Option<String>,\n    pub preserve_on_behalf_of: Option<bool>,\n    pub ws_error_handler_muted: Option<bool>,\n    #[serde(default)]\n    pub labels: Option<Vec<String>>,\n    /// Caller-intent flag (set by the CLI / git sync): when true, deploying\n    /// this flow must NOT delete an existing user draft at the same path.\n    /// Transient — never persisted.\n    #[serde(default, skip_serializing_if = \"Option::is_none\")]\n    pub skip_draft_deletion: Option<bool>,\n}\n\nimpl NewFlow {\n    pub fn parse_flow_value(&self) -> anyhow::Result<FlowValue> {\n        serde_json::from_str(self.value.get())\n            .map_err(|e| anyhow::anyhow!(\"Failed to parse flow value: {}\", e))\n    }\n}\n\n/// Body for updating an existing flow. Mirrors `NewFlow`, but `path` is optional: the\n/// flow to update is identified by the URL, so the body only needs `path` to rename it.\n/// This matches the `EditVariable` / `EditResource` / `EditApp` convention and lets a\n/// caller update in place without restating the path.\n#[derive(Debug, Deserialize)]\npub struct EditFlow {\n    #[serde(default)]\n    pub path: Option<String>,\n    pub summary: String,\n    pub description: Option<String>,\n    #[serde(deserialize_with = \"validate_flow_value\")]\n    pub value: Box<RawValue>,\n    pub schema: Option<Schema>,\n    pub tag: Option<String>,\n    pub dedicated_worker: Option<bool>,","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-types/src/flows.rs#L135-L171","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"value\": \"{\\\"modules\\\": []}\"}\n// after\n{\"value\": \"{\\\"modules\\\": [], \\\"root_module\\\": {\\\"modules\\\": [], \\\"value\\\": {\\\"type\\\": \\\"branchall\\\", \\\"branches\\\": []}}}\"}","handlingStrategy":"validation","validationCode":"// validate before sending to the flows API\nconst parsed = JSON.parse(flowValueJson); // throws on malformed JSON\nif (!Array.isArray(parsed.modules) || parsed.modules.length === 0)\n  throw new Error(\"flow value must have a non-empty 'modules' array\");\nif (!parsed.root_module) throw new Error(\"flow value must have 'root_module'\");","typeGuard":"function isFlowValue(v: unknown): v is { modules: unknown[]; root_module: unknown } {\n  return typeof v === \"object\" && v !== null && \"modules\" in v && \"root_module\" in v;\n}","tryCatchPattern":"try {\n  const flow = await wm.flows.create({ path, value });\n} catch (e) {\n  if (String(e.message).startsWith(\"Failed to parse flow value\")) {\n    console.error(\"Flow schema mismatch:\", e.message); // serde detail is embedded\n  } else throw e;\n}","preventionTips":["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"],"tags":["json","serde","flows","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}