windmill-labs/windmill · error

Flow path must be a .flow/__flow directory or a flow.yaml fi

Error message

Flow path must be a .flow/__flow directory or a flow.yaml file

What it means

`wmill flow preview` requires the given path to point either at a `.flow/__flow` directory (a folder containing flow assets) or a `flow.yaml`/`flow.json` file. Any other path form is rejected with this error before any file reading happens.

Source

Thrown at cli/src/commands/flow/flow.ts:636

  const workspace = await resolveWorkspace(opts);
  await requireLogin(opts);
  const codebases = useLocalPathScripts ? listSyncCodebases(opts) : [];

  const argPath = flowPath;
  flowPath = toSyncRootRelativePath(flowPath, cwdBeforeConfig);

  // Normalize path - ensure it's a directory path to a .flow or __flow folder
  const isFlowDir = flowPath.endsWith(".flow") || flowPath.endsWith(".flow" + SEP)
    || flowPath.endsWith("__flow") || flowPath.endsWith("__flow" + SEP);
  if (!isFlowDir) {
    // Check if it's a flow.yaml file
    if (flowPath.endsWith("flow.yaml") || flowPath.endsWith("flow.json")) {
      // Use dirname so a bare "flow.yaml" (no parent dir) becomes "."
      // instead of "" — the latter, after appending SEP below, becomes "/"
      // and silently reads from filesystem root.
      flowPath = dirname(flowPath);
    } else {
      throw new Error(
        "Flow path must be a .flow/__flow directory or a flow.yaml file"
      );
    }
  }

  if (!flowPath.endsWith(SEP)) {
    flowPath += SEP;
  }

  // The flow's windmill path (e.g. "f/cli_smoke/myrelflow"). It is what the
  // preview job runs under, and the anchor for relative-import resolution:
  // inline scripts in this flow are treated as living at
  // "<flow_wm_path>/<step_id>", so "./util" resolves to
  // "<flow_wm_path_parent>/util" — matching the keys in temp_script_refs.
  const flowWmPath = stripFlowSuffix(flowPath).replaceAll(SEP, "/");
  assertRemotePath(flowWmPath, argPath);

  // Read and parse the flow definition

View on GitHub (pinned to e474e8803c)

Solutions

  1. Point the command at the `*.flow/__flow` directory created by `wmill flow bootstrap`
  2. Rename the file to `flow.yaml` (or `flow.json`) — `.yml` is not accepted
  3. Pass the directory, not an arbitrary parent folder

Example fix

// before
wmill flow preview myflows/etl/flow.yml
// after
wmill flow preview myflows/etl/flow.yaml
Defensive patterns

Strategy: validation

Validate before calling

const ok = flowPath.endsWith('.flow/__flow') || flowPath.endsWith('flow.yaml') || flowPath.endsWith('flow.json');
if (!ok) throw new Error(`flow path must be a .flow/__flow dir or flow.yaml/json: got ${flowPath}`);

Prevention

When it happens

Trigger: Passing `wmill flow preview` a path like `myfolder/` (no `.flow/__flow` suffix), a typo'd extension such as `flow.yml`, or a path to a non-flow file.

Common situations: Typing the directory manually instead of using the scaffolded `.flow/__flow` layout; using `.yml` instead of `.yaml`; passing a script path by mistake.

Related errors


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