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

  1. Validate the flow JSON against the FlowValue schema before sending; easiest is to export a working flow from the UI and diff against it
  2. Fix the JSON type errors listed in the wrapped serde message (field names and expected types are named there)
  3. Add missing required fields (modules, root_module, etc.) or remove unknown/mistyped fields
  4. 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

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.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/db930c9319cfd880. Report an issue: GitHub.