{"record":{"id":"bf0a8f48139e7d52","repo":"argoproj/argo-workflows","slug":"couldn-t-find-parent-node-for-s","errorCode":null,"errorMessage":"couldn't find parent node for %s","messagePattern":"couldn't find parent node for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/util/util.go","lineNumber":980,"sourceCode":"\t// as well as creating temp mappings from nodeID to node\n\t// A node may appear as a child of more than one node (e.g. a task that\n\t// `depends` on several others). Only one parent is recorded, so iterate in a\n\t// deterministic order to keep the resulting parent chain, and therefore the\n\t// reset set computed by resetPath, stable across invocations.\n\tfor _, nodeID := range slices.Sorted(maps.Keys(wf.Status.Nodes)) {\n\t\twfNode := wf.Status.Nodes[nodeID]\n\t\tn := dagNode{}\n\t\tn.n = &wfNode\n\t\tnodes[wfNode.ID] = &n\n\t\tfor _, child := range wfNode.Children {\n\t\t\tparentsMap[child] = &wfNode\n\t\t}\n\t}\n\n\tfor _, wfNode := range wf.Status.Nodes {\n\t\tparentWfNode, ok := parentsMap[wfNode.ID]\n\t\tif !ok && wfNode.Name != wf.Name && !strings.HasPrefix(wfNode.Name, wf.Name+\".onExit\") {\n\t\t\treturn nil, fmt.Errorf(\"couldn't find parent node for %s\", wfNode.ID)\n\t\t}\n\n\t\tvar parentNode *dagNode\n\t\tif parentWfNode != nil {\n\t\t\tparentNode = nodes[parentWfNode.ID]\n\t\t}\n\n\t\tchildren := make([]*dagNode, 0)\n\n\t\tfor _, childID := range wfNode.Children {\n\t\t\tchildNode, ok := nodes[childID]\n\t\t\tif !ok {\n\t\t\t\treturn nil, fmt.Errorf(\"coudln't obtain child %s\", childID)\n\t\t\t}\n\t\t\tchildren = append(children, childNode)\n\t\t}\n\t\tnodes[wfNode.ID].parent = parentNode\n\t\tnodes[wfNode.ID].children = children","sourceCodeStart":962,"sourceCodeEnd":998,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/util/util.go#L962-L998","documentation":"newWorkflowsDag (workflow/util/util.go:980) builds the node graph used to compute the retry/resubmit reset path. Every node in wf.Status.Nodes must be reachable as a child of some parent node — except the workflow root node itself and onExit nodes. If a node's ID appears in no other node's Children list (and it isn't the root or an onExit node), the graph is inconsistent and this error aborts FormulateRetryWorkflow.","triggerScenarios":"Calling FormulateRetryWorkflow (or the TestDagConversion path) on a workflow whose Status.Nodes contain a node that is not listed in any other node's Children — caused by corrupted/truncated node status (e.g. status compressed/offloaded inconsistently), nodes left dangling after failed controller operations, or hand-edited workflow status.","commonSituations":"Retrying a workflow whose status was damaged by an upgrade or by exceeding node-status size limits; workflows restored from incomplete backups; status manipulated by external tools (kubectl edit) that dropped a Children entry.","solutions":["Check whether the referenced node ID (in the message) exists in the workflow's status nodes and whether any node lists it under Children; if status is corrupt, `argo retry` may not be possible.","Instead of retry, resubmit the workflow (`argo resubmit`) to create a fresh, consistent run.","Try hydrating/offloading state fixes: re-run with the controller's hydrator healthy, or upgrade argo-workflows to a version fixing the status-corruption bug you hit.","As a last resort, delete the workflow and rerun from scratch."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"wf, _ := client.ArgoprojV1alpha1().Workflows(ns).Get(ctx, name, metav1.GetOptions{})\nfor id, n := range wf.Status.Nodes {\n    hasParent := false\n    for _, p := range wf.Status.Nodes {\n        if slices.Contains(p.Children, id) { hasParent = true; break }\n    }\n    if !hasParent && n.Name != wf.Name && !strings.HasPrefix(n.Name, wf.Name+\".onExit\") {\n        fmt.Println(\"dangling node, retry will fail:\", id)\n    }\n}","typeGuard":null,"tryCatchPattern":"newWf, err := util.FormulateRetryWorkflow(ctx, wf, ...)\nif err != nil && strings.Contains(err.Error(), \"couldn't find parent node\") {\n    // status corrupt: fall back to resubmit\n    newWf, err = util.FormulateResubmitWorkflow(wf)\n}","preventionTips":["Never hand-edit workflow status.nodes with kubectl edit","Keep node status within size limits to avoid truncation corruption","Prefer resubmit over retry for workflows whose status was produced by old/buggy controller versions","Restore from complete backups only; partial status snapshots break retry"],"tags":["argo-workflows","retry","dag","node-status","corruption"],"backgroundTag":"workflow-status-corrupted","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}