plotly/plotly.js · warning
Node <nodeIndex> is already part of a group.
Error message
Node <nodeIndex> is already part of a group.
What it means
Plotly emits this warning during sankey preprocessing in convertToD3Sankey (src/traces/sankey/calc.js:50) when the trace's `arrangement.snap`/grouping attribute (`node.groups`) lists the same node index in more than one group. Only the first group containing the node is honored; later duplicates are ignored, so the grouping silently differs from what was specified.
Source
Thrown at src/traces/sankey/calc.js:50
for(i = 0; i < linkSpec.value.length; i++) {
if(linkSpec.source[i] > maxNodeId) maxNodeId = linkSpec.source[i];
if(linkSpec.target[i] > maxNodeId) maxNodeId = linkSpec.target[i];
}
var nodeCount = maxNodeId + 1;
trace.node._count = nodeCount;
// Group nodes
var j;
var groups = trace.node.groups;
var groupLookup = {};
for(i = 0; i < groups.length; i++) {
var group = groups[i];
// Build a lookup table to quickly find in which group a node is
for(j = 0; j < group.length; j++) {
var nodeIndex = group[j];
var groupIndex = nodeCount + i;
if(groupLookup.hasOwnProperty(nodeIndex)) {
Lib.warn('Node ' + nodeIndex + ' is already part of a group.');
} else {
groupLookup[nodeIndex] = groupIndex;
}
}
}
// Process links
var groupedLinks = {
source: [],
target: []
};
for(i = 0; i < linkSpec.value.length; i++) {
var val = linkSpec.value[i];
// remove negative values, but keep zeros with special treatment
var source = linkSpec.source[i];
var target = linkSpec.target[i];
if(!(val > 0 && isIndex(source, nodeCount) && isIndex(target, nodeCount))) {
continue;View on GitHub (pinned to 1d090e0b5f)
Solutions
- Remove the duplicate node index from all but one entry of node.groups so each node belongs to at most one group.
- Deduplicate programmatically before assigning: keep the first group that contains a node and drop it from the rest.
- If the overlap is intentional grouping semantics, restructure the links/nodes so one group suffices.
Example fix
// before
node: { groups: [[0, 1, 2], [2, 3, 4]] } // node 2 duplicated
// after
node: { groups: [[0, 1, 2], [3, 4]] } Defensive patterns
Strategy: validation
Validate before calling
const seen = new Set();
for (const g of nodeGroups) {
for (const n of g) {
if (seen.has(n)) throw new Error('Node ' + n + ' appears in multiple groups');
seen.add(n);
}
} Type guard
function groupsAreDisjoint(groups) {
const seen = new Set();
return groups.every(g => g.every(n => !seen.has(n) && seen.add(n)));
} Prevention
- Deduplicate node indices across groups before assigning node.groups.
- Generate groups from a partition helper rather than hand-writing arrays.
- Watch the browser console for plotly Lib.warn output in CI screenshot tests.
When it happens
Trigger: Setting layout/trace sankey `node.groups` (array of arrays of node indices) where the same node index appears in two or more sub-arrays, e.g. groups: [[0,1],[1,2]].
Common situations: Hand-built group arrays assembled programmatically or by merging user selections where overlap was not deduplicated; sankey configs generated by tools that assume groups are disjoint.
Related errors
- Ignoring coloraxis: ${colorAx} setting as it is linked to in
- Circular Sankey diagrams do not support the "input" <type>.s
- node.pad was reduced to <sankey.nodePadding()> to fit withi
- Multiple implied roots, cannot build <trace.type> hierarchy
- Total value for node <d.data.data.id> of <trace.name> is sma
AI-assisted analysis of plotly/plotly.js@1d090e0b5f (2026-09-02).
Data as JSON: /api/errors/4603382c22226ea7.
Report an issue: GitHub.