Comfy-Org/ComfyUI · error · ValueError

SeedVR2 upsample expected {self.channels} channels, got {hid

Error message

SeedVR2 upsample expected {self.channels} channels, got {hidden_states.shape[1]}.

What it means

SeedVR2VaeUpsample first projects with a 1x1 conv sized for exactly self.channels inputs, then pixel-shuffles. If the incoming hidden_states channel count differs from the block's configured channels, the projection would fail with a confusing shape error, so the block pre-checks and raises with both numbers. In a correctly built VAE this never fires; it indicates a config mismatch or a manually mis-wired block graph.

Source

Thrown at comfy/ldm/seedvr/vae.py:712

        self.spatial_up = spatial_up
        self.temporal_ratio = 2 if temporal_up else 1
        self.spatial_ratio = 2 if spatial_up else 1

        upscale_ratio = (self.spatial_ratio**2) * self.temporal_ratio
        self.upscale_conv = ops.Conv3d(
            self.channels, self.channels * upscale_ratio, kernel_size=1, padding=0
        )

        self.conv = conv

    def forward(
        self,
        hidden_states: torch.FloatTensor,
        memory_state=None,
        memory_cache=None,
    ) -> torch.FloatTensor:
        if hidden_states.shape[1] != self.channels:
            raise ValueError(f"SeedVR2 upsample expected {self.channels} channels, got {hidden_states.shape[1]}.")

        hidden_states = self.upscale_conv(hidden_states)
        b, channels, f, h, w = hidden_states.shape
        c = channels // (self.spatial_ratio * self.spatial_ratio * self.temporal_ratio)
        hidden_states = hidden_states.view(b, self.spatial_ratio, self.spatial_ratio, self.temporal_ratio, c, f, h, w)
        hidden_states = hidden_states.permute(0, 4, 5, 3, 6, 1, 7, 2).reshape(
            b,
            c,
            f * self.temporal_ratio,
            h * self.spatial_ratio,
            w * self.spatial_ratio,
        )

        if self.temporal_up and memory_state != MemoryState.ACTIVE:
            hidden_states = remove_head(hidden_states)

        hidden_states = self.conv(hidden_states, memory_state=memory_state, memory_cache=memory_cache)

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Make the upsample's channels equal the preceding block's output channels in the VAE config.
  2. Diff your VAE config against the official SeedVR2 VAE config for channel progression.
  3. If porting weights, verify each block's expected channel count from the state dict shapes and fix the config accordingly.
  4. Avoid manually inserting upsample blocks; use the standard encoder/decoder builders.
Defensive patterns

Strategy: validation

Validate before calling

def validate_upsample_input(block, hidden_states):
    if hidden_states.shape[1] != block.channels:
        raise ValueError(f"block expects {block.channels} channels, got {hidden_states.shape[1]}; fix VAE config")
    return hidden_states

Type guard

def channels_match_block(x, block) -> bool:
    return x.dim() >= 2 and x.shape[1] == block.channels

Prevention

When it happens

Trigger: Instantiating SeedVR2VaeUpsample with one channel count but feeding it a tensor from a block with a different count; editing block_out_channels inconsistently; inserting/removing a block in the encoder/decoder without updating channels.

Common situations: Hand-modified VAE configs where in_channels of the upsample does not match the previous block's out_channels; conversion scripts that miscalculate channel transitions when porting checkpoints.

Related errors


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