argoproj/argo-workflows · error

couldn't find parent node for %s

Error message

couldn't find parent node for %s

What it means

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.

Source

Thrown at workflow/util/util.go:980

	// as well as creating temp mappings from nodeID to node
	// A node may appear as a child of more than one node (e.g. a task that
	// `depends` on several others). Only one parent is recorded, so iterate in a
	// deterministic order to keep the resulting parent chain, and therefore the
	// reset set computed by resetPath, stable across invocations.
	for _, nodeID := range slices.Sorted(maps.Keys(wf.Status.Nodes)) {
		wfNode := wf.Status.Nodes[nodeID]
		n := dagNode{}
		n.n = &wfNode
		nodes[wfNode.ID] = &n
		for _, child := range wfNode.Children {
			parentsMap[child] = &wfNode
		}
	}

	for _, wfNode := range wf.Status.Nodes {
		parentWfNode, ok := parentsMap[wfNode.ID]
		if !ok && wfNode.Name != wf.Name && !strings.HasPrefix(wfNode.Name, wf.Name+".onExit") {
			return nil, fmt.Errorf("couldn't find parent node for %s", wfNode.ID)
		}

		var parentNode *dagNode
		if parentWfNode != nil {
			parentNode = nodes[parentWfNode.ID]
		}

		children := make([]*dagNode, 0)

		for _, childID := range wfNode.Children {
			childNode, ok := nodes[childID]
			if !ok {
				return nil, fmt.Errorf("coudln't obtain child %s", childID)
			}
			children = append(children, childNode)
		}
		nodes[wfNode.ID].parent = parentNode
		nodes[wfNode.ID].children = children

View on GitHub (pinned to 35bff19146)

Solutions

  1. 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.
  2. Instead of retry, resubmit the workflow (`argo resubmit`) to create a fresh, consistent run.
  3. 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.
  4. As a last resort, delete the workflow and rerun from scratch.
Defensive patterns

Strategy: fallback

Validate before calling

wf, _ := client.ArgoprojV1alpha1().Workflows(ns).Get(ctx, name, metav1.GetOptions{})
for id, n := range wf.Status.Nodes {
    hasParent := false
    for _, p := range wf.Status.Nodes {
        if slices.Contains(p.Children, id) { hasParent = true; break }
    }
    if !hasParent && n.Name != wf.Name && !strings.HasPrefix(n.Name, wf.Name+".onExit") {
        fmt.Println("dangling node, retry will fail:", id)
    }
}

Try / catch

newWf, err := util.FormulateRetryWorkflow(ctx, wf, ...)
if err != nil && strings.Contains(err.Error(), "couldn't find parent node") {
    // status corrupt: fall back to resubmit
    newWf, err = util.FormulateResubmitWorkflow(wf)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/bf0a8f48139e7d52. Report an issue: GitHub.