windmill-labs/windmill · error

step '{}' references '{}', which is not a workspace path (ex

Error message

step '{}' references '{}', which is not a workspace path (expected u/, f/, g/ or hub/). Absolute or local filesystem paths are not allowed in flow steps.

What it means

Flow validation enforces that script and flow module paths reference workspace runnables (paths starting with u/, f/, g/ or hub/). Absolute paths like /home/user/x.py or local filesystem references are rejected because the engine can only resolve workspace-hosted code, preventing accidental or unsafe local-path references.

Source

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

fn validate_flow_value<'de, D>(deserializer: D) -> Result<Box<RawValue>, D::Error>
where
    D: Deserializer<'de>,
{
    let raw_value = Box::<RawValue>::deserialize(deserializer)?;

    let flow_value: FlowValue = serde_json::from_str(raw_value.get())
        .map_err(|e| serde::de::Error::custom(format!("Invalid flow value: {}", e)))?;

    let mut validate_module = |module: &FlowModule| -> anyhow::Result<()> {
        if let Some(ref retry) = module.retry {
            validate_retry(retry, &module.id)?;
        }
        if let Ok(FlowModuleValue::Script { path, .. } | FlowModuleValue::Flow { path, .. }) =
            module.get_value()
        {
            if !is_workspace_runnable_path(&path) {
                return Err(anyhow::anyhow!(
                    "step '{}' references '{}', which is not a workspace path (expected u/, \
                     f/, g/ or hub/). Absolute or local filesystem paths are not allowed in \
                     flow steps.",
                    module.id,
                    path
                ));
            }
        }
        Ok(())
    };

    // The API is the authoritative guard (it can be called directly, bypassing the CLI), so
    // it must cover every step that resolves a path: the main modules AND the failure /
    // preprocessor modules (which can themselves be sub-flows/loops/branches).
    let extra_modules: Vec<FlowModule> = flow_value
        .failure_module
        .iter()
        .chain(flow_value.preprocessor_module.iter())

View on GitHub (pinned to e474e8803c)

Solutions

  1. Prefix the path correctly: 'u/<user>/<script>' for user scripts, 'f/<folder>/<script>' for folder scripts, or 'hub/...' for hub scripts
  2. Upload the local script to the workspace first, then reference its workspace path in the module
  3. Fix the module path in the flow editor and re-save

Example fix

// before
{"type": "script", "path": "/home/me/etl.py"}
// after
{"type": "script", "path": "u/me/etl"}
Defensive patterns

Strategy: validation

Validate before calling

function isWorkspaceRunnablePath(p) {
  return /^(u|f|g|hub)\//.test(p);
}
// before saving: flow.modules.forEach(m => {
//   if ((m.value.type === "script" || m.value.type === "flow") && !isWorkspaceRunnablePath(m.value.path))
//     throw new Error(`module ${m.id}: path ${m.value.path} is not a workspace path`);
// });

Prevention

When it happens

Trigger: Saving a flow where a Script or Flow module's `path` is e.g. '/scripts/foo.py', 'file://...', or a bare name without a workspace prefix — caught by validate_flow_value on create/update.

Common situations: Migrating scripts from local directories into flows, copying paths from CLI invocations of local files, typos omitting the u/ or f/ prefix, or generated flows from AI/tooling that emit raw file paths.

Related errors


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