{"record":{"id":"1f27d068c0238c09","repo":"windmill-labs/windmill","slug":"groups-a-id-and-b-id-overlap-without-nes","errorCode":null,"errorMessage":"Groups '${a.id}' and '${b.id}' overlap without nesting","messagePattern":"Groups '(.+?)' and '(.+?)' overlap without nesting","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/graph/flowStructure.ts","lineNumber":129,"sourceCode":"\t\t\totherGroups.push(g)\n\t\t}\n\t}\n\n\t// Validate no partial overlaps\n\tfor (let i = 0; i < levelGroups.length; i++) {\n\t\tfor (let j = i + 1; j < levelGroups.length; j++) {\n\t\t\tconst a = levelGroups[i]\n\t\t\tconst b = levelGroups[j]\n\t\t\tconst aStart = indexMap.get(a.start_id)!\n\t\t\tconst aEnd = indexMap.get(a.end_id)!\n\t\t\tconst bStart = indexMap.get(b.start_id)!\n\t\t\tconst bEnd = indexMap.get(b.end_id)!\n\n\t\t\tif (aEnd < bStart || bEnd < aStart) continue\n\t\t\tif (aStart <= bStart && bEnd <= aEnd) continue\n\t\t\tif (bStart <= aStart && aEnd <= bEnd) continue\n\n\t\t\tthrow new Error(`Groups '${a.id}' and '${b.id}' overlap without nesting`)\n\t\t}\n\t}\n\n\t// Build grouped structure for this level\n\tfunction build(\n\t\tstartIdx: number,\n\t\tendIdx: number,\n\t\tavailableGroups: GraphGroup[]\n\t): FlowStructureNode[] {\n\t\tconst result: FlowStructureNode[] = []\n\t\tlet i = startIdx\n\t\twhile (i <= endIdx) {\n\t\t\tconst candidates = availableGroups.filter((g) => {\n\t\t\t\tconst gStart = indexMap.get(g.start_id)!\n\t\t\t\tconst gEnd = indexMap.get(g.end_id)!\n\t\t\t\treturn gStart === i && gEnd <= endIdx\n\t\t\t})\n\t\t\tcandidates.sort((a, b) => {","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/graph/flowStructure.ts#L111-L147","documentation":"Two sibling groups at the same level must be either disjoint or strictly nested. This throw fires when two groups partially overlap (each has nodes the other lacks), which cannot be expressed as a hierarchy of nested regions in the graph.","triggerScenarios":"Two GraphGroups a and b where ranges [aStart,aEnd] and [bStart,bEnd] intersect but neither contains the other — e.g. group1 covers steps 1-3 and group2 covers steps 2-5.","commonSituations":"Editing a flow and dragging a step into/out of a branch while stale group boundaries persist; duplicated group ids with shifted boundaries after a merge; imported flow JSON with hand-drawn group boxes that cross each other.","solutions":["Open the flow and adjust the two groups so one fully contains the other, or shrink them so they no longer overlap.","Delete and redraw the conflicting group(s) in the editor to regenerate consistent boundaries.","Compare the deployed flow JSON groups and fix the overlapping start_id/end_id pairs manually.","If a merge introduced it, redo the merge keeping group definitions from one side only."],"exampleFix":"// before\ngroups: [{ id: 'a', start_id: 's1', end_id: 's3' }, { id: 'b', start_id: 's2', end_id: 's5' }]\n// after\ngroups: [{ id: 'a', start_id: 's1', end_id: 's5' }] // b nested or removed","handlingStrategy":"validation","validationCode":"for (let i = 0; i < groups.length; i++) for (let j = i + 1; j < groups.length; j++) {\n  const a = groups[i], b = groups[j]\n  const nested = (as <= bs && be <= ae) || (bs <= as && ae <= be)\n  const disjoint = ae < bs || be < as\n  if (!nested && !disjoint) console.warn('overlap', a.id, b.id)\n}","typeGuard":"function groupsAreHierarchical(groups, indexMap) {\n  return groups.every((a, i) => groups.every((b, j) => i >= j || (fn(indexMap, a, b) || fn(indexMap, b, a))))\n}\nconst fn = (m, a, b) => { const as=m.get(a.start_id), ae=m.get(a.end_id), bs=m.get(b.start_id), be=m.get(b.end_id); return ae<bs || be<as || (as<=bs && be<=ae) }","tryCatchPattern":"try { tree = buildStructureTree(items, groups) } catch (e) { if (String(e.message).includes('overlap without nesting')) showGroupConflictDialog(e); else throw e }","preventionTips":["Redraw groups in the editor instead of hand-editing boundaries","Resolve overlapping groups from merges by keeping one side's definitions","Run a hierarchical-consistency check on imported flows before rendering"],"tags":["graph","flow-structure","grouping"],"backgroundTag":"overlapping-group-ranges","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}