Comfy-Org/ComfyUI · error · ValueError

MergeSplat: batch size mismatch ({b} vs {g.positions.shape[0

Error message

MergeSplat: batch size mismatch ({b} vs {g.positions.shape[0]}).

What it means

Raised by _merge_gaussians when the input SPLATs disagree on batch size (positions.shape[0]). Merge is defined per batch item — it concatenates each item's gaussians across inputs and pads SH to the max degree — so every input must carry the same number of items. The first input's batch size is the reference; any deviation raises with both values.

Source

Thrown at comfy_extras/nodes_gaussian_splat.py:1186

def _pad_stack(items, n):
    # Stack a list of (Lᵢ, *tail) tensors into (B, n, *tail), zero-padding each row up to n.
    tail = items[0].shape[1:]
    out = items[0].new_zeros((len(items), n, *tail))
    for i, t in enumerate(items):
        out[i, :t.shape[0]] = t
    return out


def _merge_gaussians(gaussians: list) -> Types.SPLAT:
    # Concatenate SPLAT batches along the splat dimension (per item), padding SH to the highest degree.
    gs = [g for g in gaussians if g is not None]
    if not gs:
        raise ValueError("MergeSplat: no gaussians to merge")
    b = gs[0].positions.shape[0]
    for g in gs:
        if g.positions.shape[0] != b:
            raise ValueError(f"MergeSplat: batch size mismatch ({b} vs {g.positions.shape[0]}).")
    max_k = max(g.sh.shape[2] for g in gs)

    pos_b, scl_b, rot_b, op_b, sh_b, lengths = [], [], [], [], [], []
    for i in range(b):
        pos_i, scl_i, rot_i, op_i, sh_i = [], [], [], [], []
        for g in gs:
            end = _real_len(g, i)
            pos_i.append(g.positions[i, :end])
            scl_i.append(g.scales[i, :end])
            rot_i.append(g.rotations[i, :end])
            op_i.append(g.opacities[i, :end])
            sh = g.sh[i, :end]       # (end, K, 3)
            if sh.shape[1] < max_k:  # zero-pad lower-degree SH
                sh = torch.cat([sh, sh.new_zeros(sh.shape[0], max_k - sh.shape[1], sh.shape[2])], dim=1)
            sh_i.append(sh)
        pos_b.append(torch.cat(pos_i))
        scl_b.append(torch.cat(scl_i))
        rot_b.append(torch.cat(rot_i))

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Make all merged splats share a batch size: select the same batch item (slice/re-batch) before merging.
  2. If one input is single-item, expand or pick matching items so shapes align.
  3. Check each upstream node's batch dimension (positions.shape[0]) and align them.

Example fix

# before: batch sizes 1 and 4
merged = _merge_gaussians([splat_b1, splat_b4])

# after: align to the same item count
merged = _merge_gaussians([splat_b1, splat_b4[0:1]])
Defensive patterns

Strategy: validation

Validate before calling

sizes = {g.positions.shape[0] for g in gs}
if len(sizes) > 1:
    raise ValueError(f'MergeSplat batch mismatch: {sizes}; align batch sizes first')
merged = _merge_gaussians(gs)

Type guard

def same_batch_size(gs: list) -> bool:
    return len({g.positions.shape[0] for g in gs}) == 1

Try / catch

try:
    merged = _merge_gaussians(gs)
except ValueError as e:
    if 'batch size mismatch' in str(e):
        b = gs[0].positions.shape[0]
        gs = [g[:b] for g in gs]  # align to first input's batch
        merged = _merge_gaussians(gs)
    else:
        raise

Prevention

When it happens

Trigger: Merging a splat with batch size 1 against one with batch size 4 (e.g., one decoded from a batched latent, another loaded from a single-item file via File3DToSplat); mixing sources with different item counts in MergeSplat.

Common situations: One input from a batched generation node and another from a single loaded file; upstream nodes that changed batch handling after a workflow edit.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/117eed61f787158b. Report an issue: GitHub.