{"record":{"id":"5284cc89f2f4e9c2","repo":"Comfy-Org/ComfyUI","slug":"dinov2model-forward-is-the-backward-compatible-c","errorCode":null,"errorMessage":"Dinov2Model.forward() is the backward-compatible CLIP-vision path and does not apply DA3 extensions (RoPE, alternating attention, camera-token injection). Use get_intermediate_layers_da3() for Depth Anything 3 models.","messagePattern":"Dinov2Model\\.forward\\(\\) is the backward-compatible CLIP-vision path and does not apply DA3 extensions \\(RoPE, alternating attention, camera-token injection\\)\\. Use get_intermediate_layers_da3\\(\\) for Depth Anything 3 models\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"comfy/image_encoders/dino2.py","lineNumber":339,"sourceCode":"\n        # camera_token shape: (1, 2, dim) -> (ref_token, src_token).\n        num_cam_tokens = 2 if self.alt_start != -1 else 0\n\n        self.embeddings = Dino2Embeddings(\n            dim, dtype, device, operations,\n            patch_size=patch_size, image_size=image_size,\n            use_mask_token=use_mask_token, num_camera_tokens=num_cam_tokens,\n        )\n        self.encoder = Dino2Encoder(\n            dim, heads, layer_norm_eps, num_layers, dtype, device, operations,\n            use_swiglu_ffn=use_swiglu_ffn,\n            qknorm_start=self.qknorm_start,\n        )\n        self.layernorm = operations.LayerNorm(dim, eps=layer_norm_eps, dtype=dtype, device=device)\n\n    def forward(self, pixel_values, attention_mask=None, intermediate_output=None):\n        if self.alt_start != -1:\n            raise RuntimeError(\n                \"Dinov2Model.forward() is the backward-compatible CLIP-vision path and does not \"\n                \"apply DA3 extensions (RoPE, alternating attention, camera-token injection). \"\n                \"Use get_intermediate_layers_da3() for Depth Anything 3 models.\"\n            )\n        x = self.embeddings(pixel_values)\n        x, i = self.encoder(x, intermediate_output=intermediate_output)\n        x = self.layernorm(x)\n        pooled_output = x[:, 0, :]\n        return x, i, pooled_output, None\n\n    def get_intermediate_layers(self, pixel_values, indices, apply_norm=True):\n        \"\"\"Single-view multi-layer feature extraction.\"\"\"\n        x = self.embeddings(pixel_values)\n        optimized_attention = optimized_attention_for_device(x.device, False, small_input=True)\n        n_layers = len(self.encoder.layer)\n        resolved = [(i if i >= 0 else n_layers + i) for i in indices]\n        target = set(resolved)\n        max_idx = max(resolved)","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy/image_encoders/dino2.py#L321-L357","documentation":"Raised by Dinov2Model.forward when the model was configured with DA3 (Depth Anything 3) extensions — indicated by alt_start != -1 (alternating attention) plus options like RoPE and camera tokens. The plain forward() only implements the classic DINOv2/CLIP-vision path; feeding a DA3-configured model through it would silently produce features without those extensions, so ComfyUI raises RuntimeError and points you to get_intermediate_layers_da3().","triggerScenarios":"Loading a Depth Anything 3 checkpoint (which sets num_camera_tokens / alt_start / qknorm_start in config) and then calling model.forward(...) or routing it through code that assumes the CLIPVision API (e.g. a generic CLIPVisionEncoder node or old custom code) instead of the DA3 feature-extraction entry point.","commonSituations":"Custom CLIP-vision nodes written before DA3 support that call forward() unconditionally; adapting another vision model's adapter to DA3 checkpoints; mixing DA3 checkpoints with nodes built for plain DINOv2 depth models.","solutions":["Call get_intermediate_layers_da3() (the DA3 path) for Depth Anything 3 models — it applies RoPE, alternating attention, and camera-token handling","Use the stock Depth Anything 3 nodes shipped with ComfyUI instead of a generic CLIP-vision encode node","For non-DA3 DINOv2 checkpoints, forward() is fine; verify alt_start == -1 before choosing the API"],"exampleFix":"# before\nx, i, pooled, _ = dinov2_model.forward(pixels)  # raises for DA3 configs\n# after\nif dinov2_model.alt_start != -1:\n    feats = dinov2_model.get_intermediate_layers_da3(pixels, ...)\nelse:\n    x, i, pooled, _ = dinov2_model.forward(pixels)","handlingStrategy":"type-guard","validationCode":"if getattr(dinov2_model, 'alt_start', -1) != -1:\n    feats = dinov2_model.get_intermediate_layers_da3(pixel_values, idx)\nelse:\n    x, i, pooled, _ = dinov2_model.forward(pixel_values)","typeGuard":"def is_da3_model(model) -> bool:\n    return getattr(model, 'alt_start', -1) != -1 or getattr(model, 'num_camera_tokens', 0) not in (None, 0)","tryCatchPattern":"try:\n    out = model.forward(pixel_values)\nexcept RuntimeError:\n    out = model.get_intermediate_layers_da3(pixel_values, ...)","preventionTips":["Branch vision-encoder code on alt_start/num_camera_tokens before choosing the API","Use the stock DA3 nodes for Depth Anything 3 checkpoints"],"tags":["vision-encoder","dino2","depth-anything","api-misuse","model-loading"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}