gitbutlerapp/gitbutler · error

Invalid parent delimitation: requested child is not a direct

Error message

Invalid parent delimitation: requested child is not a direct parent of target.child

What it means

`Editor::disconnect_segment_from` validates that every selector in `children_to_disconnect` appears among the incoming edges of `target.child`; this error means a selected 'child' is not directly adjacent. Note the message text is wrong in the source: it says the child "is not a direct parent of target.child" — a copy-paste from the parent case — but the check is against direct children. Trust the condition, not the wording.

Source

Thrown at crates/but-rebase/src/graph_rebase/mutate.rs:464

            .iter()
            .map(|(_, _, edge_source)| *edge_source)
            .collect::<HashSet<_>>();

        // 1. Verify that all parents and children to disconnect are directly connected to the target segment.
        if let Some(parents_to_disconnect) = parents_to_disconnect.as_ref() {
            for selector in parents_to_disconnect {
                if !available_parents.contains(&selector.id) {
                    return Err(anyhow!(
                        "Invalid parent delimitation: requested parent is not a direct parent of target.parent"
                    ));
                }
            }
        }

        if let Some(children_to_disconnect) = children_to_disconnect.as_ref() {
            for selector in children_to_disconnect {
                if !available_children.contains(&selector.id) {
                    return Err(anyhow!(
                        "Invalid parent delimitation: requested child is not a direct parent of target.child"
                    ));
                }
            }
        }

        let parent_ids_to_disconnect = parents_to_disconnect
            .as_ref()
            .map(|parents| parents.iter().map(|s| s.id).collect::<HashSet<_>>());
        let child_ids_to_disconnect = children_to_disconnect
            .as_ref()
            .map(|children| children.iter().map(|s| s.id).collect::<HashSet<_>>());

        let mut disconnected_parent_edges = Vec::new();
        // 2. Disconnect parents.
        for (edge_id, edge_weight, edge_target) in outgoing_edges {
            let should_disconnect = parent_ids_to_disconnect
                .as_ref()

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Enumerate incoming edges of `target.child` and select children only from that set
  2. Recompute selectors from the live editor graph right before the call
  3. Fix upstream (optional): correct the message to 'requested child is not a direct child of target.child' to avoid future confusion

Example fix

// before
let children = SelectorSet::Some(SomeSelectors::new(user_selected)?); // may include non-adjacent ids
editor.disconnect_segment_from(target, children, parents, false)?; // Err

// after — derive children from the graph's actual edges
let adjacent: Vec<AnySelector> = graph
    .edges_directed(target_child_id, petgraph::Direction::Incoming)
    .map(|e| AnySelector::Commit(e.source().attach(repo)))
    .collect();
let children = SelectorSet::Some(SomeSelectors::new(adjacent)?);
Defensive patterns

Strategy: validation

Validate before calling

// Restrict candidate children to nodes directly connected to target.child:
let adjacent: Vec<_> = graph
    .edges_directed(target_child_id, petgraph::Direction::Incoming)
    .map(|e| e.source())
    .collect();
anyhow::ensure!(
    requested_children.iter().all(|c| adjacent.contains(c)),
    "non-adjacent child requested"
);

Prevention

When it happens

Trigger: Passing a grandchild, a commit on another lane, or a stale id in `children_to_disconnect`; selectors computed from an outdated graph snapshot whose incoming edges differ.

Common situations: UI multi-select including non-adjacent commits as 'children'; concurrent graph edits between computing selectors and disconnecting; tests with fixtures whose topology changed.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/1386dec7a36c1ade. Report an issue: GitHub.