{"record":{"id":"47453ffcd5b2f827","repo":"windmill-labs/windmill","slug":"flow-path-must-be-a-flow-flow-directory-or-a-fl","errorCode":null,"errorMessage":"Flow path must be a .flow/__flow directory or a flow.yaml file","messagePattern":"Flow path must be a \\.flow/__flow directory or a flow\\.yaml file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/flow/flow.ts","lineNumber":636,"sourceCode":"  const workspace = await resolveWorkspace(opts);\n  await requireLogin(opts);\n  const codebases = useLocalPathScripts ? listSyncCodebases(opts) : [];\n\n  const argPath = flowPath;\n  flowPath = toSyncRootRelativePath(flowPath, cwdBeforeConfig);\n\n  // Normalize path - ensure it's a directory path to a .flow or __flow folder\n  const isFlowDir = flowPath.endsWith(\".flow\") || flowPath.endsWith(\".flow\" + SEP)\n    || flowPath.endsWith(\"__flow\") || flowPath.endsWith(\"__flow\" + SEP);\n  if (!isFlowDir) {\n    // Check if it's a flow.yaml file\n    if (flowPath.endsWith(\"flow.yaml\") || flowPath.endsWith(\"flow.json\")) {\n      // Use dirname so a bare \"flow.yaml\" (no parent dir) becomes \".\"\n      // instead of \"\" — the latter, after appending SEP below, becomes \"/\"\n      // and silently reads from filesystem root.\n      flowPath = dirname(flowPath);\n    } else {\n      throw new Error(\n        \"Flow path must be a .flow/__flow directory or a flow.yaml file\"\n      );\n    }\n  }\n\n  if (!flowPath.endsWith(SEP)) {\n    flowPath += SEP;\n  }\n\n  // The flow's windmill path (e.g. \"f/cli_smoke/myrelflow\"). It is what the\n  // preview job runs under, and the anchor for relative-import resolution:\n  // inline scripts in this flow are treated as living at\n  // \"<flow_wm_path>/<step_id>\", so \"./util\" resolves to\n  // \"<flow_wm_path_parent>/util\" — matching the keys in temp_script_refs.\n  const flowWmPath = stripFlowSuffix(flowPath).replaceAll(SEP, \"/\");\n  assertRemotePath(flowWmPath, argPath);\n\n  // Read and parse the flow definition","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/flow/flow.ts#L618-L654","documentation":"`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.","triggerScenarios":"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.","commonSituations":"Typing the directory manually instead of using the scaffolded `.flow/__flow` layout; using `.yml` instead of `.yaml`; passing a script path by mistake.","solutions":["Point the command at the `*.flow/__flow` directory created by `wmill flow bootstrap`","Rename the file to `flow.yaml` (or `flow.json`) — `.yml` is not accepted","Pass the directory, not an arbitrary parent folder"],"exampleFix":"// before\nwmill flow preview myflows/etl/flow.yml\n// after\nwmill flow preview myflows/etl/flow.yaml","handlingStrategy":"validation","validationCode":"const ok = flowPath.endsWith('.flow/__flow') || flowPath.endsWith('flow.yaml') || flowPath.endsWith('flow.json');\nif (!ok) throw new Error(`flow path must be a .flow/__flow dir or flow.yaml/json: got ${flowPath}`);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always bootstrap flows with `wmill flow bootstrap` so the directory layout is canonical","Use `.yaml` extension, never `.yml`","Quote paths in shell scripts to avoid truncation","Tab-complete the directory path instead of typing it"],"tags":["cli","path-validation","argument-error"],"backgroundTag":"invalid-path-argument","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"}