windmill-labs/windmill · error

{}

Error message

{}

What it means

FlowModule::get_value deserializes the module's raw `value` JSON column into FlowModuleValue. Since the column is stored as untyped JSON, any shape mismatch (unknown or invalid 'type' discriminant, missing fields for that type, malformed JSON) surfaces as the raw serde error wrapped with this empty message.

Source

Thrown at backend/windmill-types/src/flows.rs:647

}

#[derive(Deserialize)]
pub struct BranchWithSkipFailures {
    pub skip_failure: Option<bool>,
}

#[derive(Deserialize)]
pub struct FlowModuleWithBranches {
    pub branches: Vec<BranchWithSkipFailures>,
}

impl FlowModule {
    pub fn id_append(&mut self, s: &str) {
        self.id = format!("{}-{}", self.id, s);
    }
    pub fn get_value(&self) -> anyhow::Result<FlowModuleValue> {
        serde_json::from_str::<FlowModuleValue>(self.value.get())
            .map_err(|e| anyhow::anyhow!("{}", e))
    }

    pub fn get_value_with_skip_failures(&self) -> anyhow::Result<FlowModuleValueWithSkipFailures> {
        serde_json::from_str::<FlowModuleValueWithSkipFailures>(self.value.get())
            .map_err(|e| anyhow::anyhow!("{}", e))
    }

    pub fn get_branches_skip_failures(&self) -> anyhow::Result<FlowModuleWithBranches> {
        serde_json::from_str::<FlowModuleWithBranches>(self.value.get())
            .map_err(|e| anyhow::anyhow!("{}", e))
    }

    pub fn is_flow(&self) -> bool {
        self.get_type().is_ok_and(|x| x == "flow")
    }

    pub fn get_value_with_parallel(&self) -> anyhow::Result<FlowModuleValueWithParallel> {
        serde_json::from_str::<FlowModuleValueWithParallel>(self.value.get())

View on GitHub (pinned to e474e8803c)

Solutions

  1. Read the wrapped serde message for the exact field/discriminant mismatch
  2. Re-save the module from the flow editor so the current schema serializes it
  3. Fix the 'type' field to a valid FlowModuleValue variant and include its required fields
  4. Check for frontend/backend version skew after an upgrade

Example fix

// before
{"type": "scrip", "path": "u/x/y"}
// after
{"type": "script", "input_transforms": {}, "path": "u/x/y"}
Defensive patterns

Strategy: validation

Validate before calling

function moduleValueTypeIsValid(moduleValueJson) {
  const VALID = ["rawscript","script","flow","branchall","branchone","forloop","whileloop","loop","aiagent","failure","approval","sleep","wait","http","websocket","graphql","input","identity","dependabot"];
  try { const v = JSON.parse(moduleValueJson); return VALID.includes(v?.type); } catch { return false; }
}

Type guard

function hasModuleType(m) {
  try { return typeof JSON.parse(m.value).type === "string"; } catch { return false; }
}

Try / catch

match module.get_value() {
    Ok(v) => use_value(v),
    Err(e) => log::error!("corrupt module {}: {}", module.id, e), // serde detail included
}

Prevention

When it happens

Trigger: Any code path calling flow_module.get_value() on a module whose stored JSON doesn't deserialize into FlowModuleValue — e.g. flow execution, editing, or traversal after a schema change or corrupt write.

Common situations: Old flow modules saved before a FlowModuleValue enum variant changed name/shape, hand-edited module JSON, corrupt DB rows, or deploys from mismatched frontend/backend versions.

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/59c7c100179ba5f1. Report an issue: GitHub.