apache/superset · error · ValidationError
Cycle detected: {uuid} appears in its ancestry
Error message
Cycle detected: {uuid} appears in its ancestry What it means
Raised inside validate_folders()'s BFS when a folder uuid reappears in its own ancestry path — the tree built from client-supplied folders has a cycle. The path list accumulates ancestor uuids during traversal and this check fires when the current node's uuid is already in that path.
Source
Thrown at superset/commands/dataset/update.py:452
"""
Additional folder validation.
The marshmallow schema will validate the folder structure, but we still need to
check that UUIDs are valid, names are unique and not reserved, and that there are
no cycles.
"""
if not is_feature_enabled("DATASET_FOLDERS"):
raise ValidationError("Dataset folders are not enabled")
queue: list[tuple[FolderSchema, list[UUID]]] = [(folder, []) for folder in folders]
seen_uuids = set()
seen_fqns = set() # fully qualified folder names
while queue:
obj, path = queue.pop(0)
uuid, name = obj["uuid"], obj.get("name")
if uuid in path:
raise ValidationError(f"Cycle detected: {uuid} appears in its ancestry")
if uuid in seen_uuids:
raise ValidationError(f"Duplicate UUID in folder structure: {uuid}")
seen_uuids.add(uuid)
# folders can have duplicate name as long as they're not siblings
if name:
fqn = tuple(path + [name])
if name and fqn in seen_fqns:
raise ValidationError(f"Duplicate folder name: {name}")
seen_fqns.add(fqn)
# Allow default folders (by UUID) to use reserved names
if (
name.lower() in {"metrics", "columns"}
and str(uuid) not in DEFAULT_FOLDER_UUIDS
):
raise ValidationError(f"Folder cannot have name '{name}'")View on GitHub (pinned to f4587218dd)
Solutions
- Inspect the folders payload and break the loop: remove the back-reference that closes the cycle (the uuid in the message is the offending node).
- Regenerate the folder tree from the server's current state (GET the dataset, modify only the intended node) rather than building it from scratch.
- Add a pre-flight cycle check in your client (see validationCode).
Example fix
// before
folders = [{uuid: A, children: [{uuid: B, children: [{uuid: A}]}]}] // cycle A->B->A
// after
folders = [{uuid: A, children: [{uuid: B}]}] Defensive patterns
Strategy: validation
Validate before calling
def has_cycle(folders):
def visit(node, path):
if node["uuid"] in path:
return True
return any(visit(c, path + [node["uuid"]]) for c in node.get("children", []))
return any(visit(f, []) for f in folders)
assert not has_cycle(payload["folders"]), "cycle in folder tree" Try / catch
try:
UpdateDatasetCommand(...).run()
except DatasetInvalidError as ex:
if any("Cycle detected" in str(e) for e in ex.exceptions):
rebuild_tree_from_server_state() Prevention
- Never hand-nest folder JSON; mutate the tree returned by GET.
- Run a DFS cycle check in clients that support drag-and-drop re-parenting.
- Log the offending uuid from the message when it fires.
When it happens
Trigger: PUT /api/v1/dataset/{id} with a folders payload where a child references an ancestor as its own descendant (e.g. folder A lists folder B under children, and B lists A under children), directly or transitively.
Common situations: Hand-edited folder JSON, or frontend state corruption after drag-and-drop re-parenting produces a loop. Programmatic folder generation that links the last node back to the root.
Related errors
- Duplicate UUID in folder structure: {uuid}
- Duplicate folder name: {name}
- Folder cannot have name '{name}'
- Invalid UUID: {uuid}
- Dataset parameters are invalid.
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/87297afc2de71072.
Report an issue: GitHub.