{"record":{"id":"f0dbb953c06c11fb","repo":"Comfy-Org/ComfyUI","slug":"either-spatial-upsample-or-temporal-upsample-must","errorCode":null,"errorMessage":"Either spatial_upsample or temporal_upsample must be True","messagePattern":"Either spatial_upsample or temporal_upsample must be True","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy/ldm/lightricks/latent_upsampler.py","lineNumber":214,"sourceCode":"                PixelShuffleND(3),\n            )\n        elif spatial_upsample:\n            if rational_resampler:\n                self.upsampler = SpatialRationalResampler(\n                    mid_channels=mid_channels, scale=self.spatial_scale, operations=operations\n                )\n            else:\n                self.upsampler = nn.Sequential(\n                    operations.Conv2d(mid_channels, 4 * mid_channels, kernel_size=3, padding=1),\n                    PixelShuffleND(2),\n                )\n        elif temporal_upsample:\n            self.upsampler = nn.Sequential(\n                operations.Conv3d(mid_channels, 2 * mid_channels, kernel_size=3, padding=1),\n                PixelShuffleND(1),\n            )\n        else:\n            raise ValueError(\n                \"Either spatial_upsample or temporal_upsample must be True\"\n            )\n\n        self.post_upsample_res_blocks = nn.ModuleList(\n            [ResBlock(mid_channels, dims=dims, operations=operations) for _ in range(num_blocks_per_stage)]\n        )\n\n        self.final_conv = Conv(mid_channels, in_channels, kernel_size=3, padding=1)\n\n    def get_dtype(self):\n        return getattr(self.initial_conv, \"weight_comfy_model_dtype\", self.initial_conv.weight.dtype)\n\n    def forward(self, latent: torch.Tensor) -> torch.Tensor:\n        b, c, f, h, w = latent.shape\n\n        if self.dims == 2:\n            x = rearrange(latent, \"b c f h w -> (b f) c h w\")\n            x = self.initial_conv(x)","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/ldm/lightricks/latent_upsampler.py#L196-L232","documentation":"Each upsampler stage must increase either spatial resolution (2D pixel-shuffle after a Conv2d) or temporal length (Conv3d + 1D pixel-shuffle). If both flags are False the block would be an identity chain with a final conv, which is not a supported configuration, so the constructor rejects it.","triggerScenarios":"Building the upsampler with spatial_upsample=False, temporal_upsample=False; typically a config where one flag was expected to default True but was explicitly disabled, or a yaml with a typo making both false.","commonSituations":"Config generation code that sets flags from a mode string and falls through to False/False, or disabling temporal upsampling on a stage that also had spatial off.","solutions":["Enable at least one of spatial_upsample or temporal_upsample per stage","If you truly need a non-upsampling residual stage, use the plain ResBlock stack classes instead of this upsampler","Audit the config loader for boolean coercion bugs (e.g. 'false' strings, missing keys defaulting wrong)"],"exampleFix":"# before\nstage = UpsampleStage(..., spatial_upsample=False, temporal_upsample=False)\n# after\nstage = UpsampleStage(..., spatial_upsample=True, temporal_upsample=False)","handlingStrategy":"validation","validationCode":"assert spatial_upsample or temporal_upsample, \"pick at least one upsample mode\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate stage configs as a whole (mode -> both flags) instead of independent booleans","Add a config round-trip test for every stage combo you ship"],"tags":["ltx","upsample","config","init"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}