{"record":{"id":"954baa6c1a5090bc","repo":"windmill-labs/windmill","slug":"skipping-cyclic-length-script-s-on-a-dependenc","errorCode":null,"errorMessage":"Skipping ${cyclic.length} script(s) on a dependency cycle: ${cyclic.sort().join(\", \")}","messagePattern":"Skipping (.+?) script\\(s\\) on a dependency cycle: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cli/src/commands/pipeline/pipeline.ts","lineNumber":873,"sourceCode":"      if (reachable.has(e)) {\n        reachableEnds.push(e);\n      } else {\n        droppedEnds.push(e);\n        log.warn(\n          `end '${idLabel(e)}' is only reachable through a skipped input/event handler — not run (bind it with --upload to include it).`,\n        );\n      }\n    }\n  }\n\n  // Selections can still pull a non-runnable node in via graph reachability (e.g.\n  // whole-pipeline mode collects every root's closure) — drop macro libraries and\n  // local-only display nodes before ordering so they never run.\n  for (const p of notRunnablePaths) selectedScripts.delete(p);\n\n  const { order, cyclic } = topoOrder(graph, selectedScripts);\n  if (cyclic.length > 0) {\n    log.warn(`Skipping ${cyclic.length} script(s) on a dependency cycle: ${cyclic.sort().join(\", \")}`);\n  }\n\n  // `// partitioned` scripts need a resolved `partition` arg. Deployed runs get\n  // it from backend run-start resolution, but previews (`--local`) never do —\n  // so resolve it client-side there: `--partition` wins; otherwise time kinds\n  // default to the current UTC period (mirroring the backend defaults; custom\n  // `tz=`/`format=`/`start=` opts are a backend concern — pass --partition\n  // explicitly to match them). `dynamic` has no default. For deployed runs the\n  // arg is only injected when `--partition` is given (an explicit backfill).\n  const partitionKindByPath = new Map(\n    graph.runnables\n      .filter((r) => r.usage_kind === \"script\" && r.partition_kind)\n      .map((r) => [r.path, r.partition_kind!]),\n  );\n  const partitionValueFor = (nodePath: string): string | undefined => {\n    const kind = partitionKindByPath.get(nodePath);\n    if (!kind) return undefined;\n    if (opts.partition) return opts.partition;","sourceCodeStart":855,"sourceCodeEnd":891,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/cli/src/commands/pipeline/pipeline.ts#L855-L891","documentation":"During `wmill pipeline run`, topoOrder orders the selected scripts; any scripts that form a dependency cycle cannot be ordered and are excluded from the run, with this warning listing them. Running a cyclic subset is impossible, so the CLI drops those nodes rather than deadlocking.","triggerScenarios":"The selected window of the pipeline DAG contains a cycle (script A depends on B which depends on A), e.g. after a misconfigured dependency edge or a hand-edited pipeline definition.","commonSituations":"Accidentally adding a dependency edge backwards while editing the flow; importing a pipeline whose generated dependencies form a loop; macro/library scripts referencing each other.","solutions":["Open the pipeline in the UI and remove/reverse the dependency edge that closes the cycle.","Check the listed paths (the warning sorts them) and trace their mutual dependencies.","Re-run once the DAG is acyclic — the skipped scripts will then be included.","If the cycle is intentional display-only wiring, keep it out of the runnable selection (macro libraries/local display nodes are normally filtered)."],"exampleFix":"// before: a depends on b, b depends on a -> both skipped\n// after (edit pipeline definition): remove a's dependency on b\n// a: depends: [b]  ->  a: depends: []","handlingStrategy":"validation","validationCode":"// detect cycles in the dependency graph before running\nfunction hasCycle(nodes) {\n  const state = {};\n  function visit(n) {\n    if (state[n] === 1) return true;\n    if (state[n] === 2) return false;\n    state[n] = 1;\n    for (const d of depsOf(n)) if (visit(d)) return true;\n    state[n] = 2;\n    return false;\n  }\n  return Object.keys(nodes).some(visit);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Review dependency edges when editing the flow; avoid mutual references.","Run the whole pipeline once after structural edits to surface cycles early.","Treat the sorted list in this warning as the exact nodes needing an edge removed.","Keep macro/display-only wiring out of runnable script dependencies."],"tags":["cli","pipeline","dependency-cycle","dag"],"backgroundTag":"dependency-cycle-detected","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"}