{"record":{"id":"14d3c9eee7aab8ac","repo":"screenpipe/screenpipe","slug":"rb-split","errorCode":null,"errorMessage":"rb split","messagePattern":"rb split","errorType":"exception","errorClass":"Error::Inference","httpStatus":null,"severity":"error","filePath":"crates/screenpipe-rfdetr-mlx/src/decoder/mod.rs","lineNumber":678,"sourceCode":"        let qp0a = relu(&qp0)?;\n        let query_pos = linear(&qp0a, &self.ref_point_head_w1, &self.ref_point_head_b1)?;\n\n        // Decoder layer loop — uses RAW projector output (`tokens_flat`)\n        // as memory, not enc_memory. No per-layer eval — let MLX\n        // schedule the graph; the lazy-graph stack-overflow problem\n        // we hit in the backbone (12 blocks deep) is much smaller here\n        // (just 2 layers).\n        for l in &self.layers {\n            output = l.forward(&output, tokens_flat, &query_pos, &refpoints_input)?;\n        }\n        // Final LN.\n        output = ln(&output, &self.final_norm_w, &self.final_norm_b)?;\n\n        // Final heads.\n        let logits = linear(&output, &self.class_head_w, &self.class_head_b)?;\n        let bbox_delta = self.bbox_head.forward(&output)?;\n        // Final bbox refinement vs. refpoint_embed (cxcywh).\n        let rb_parts = ops::split_sections(&refpoint_embed, &[2], -1).map_err(err(\"rb split\"))?;\n        let bd_parts = ops::split_sections(&bbox_delta, &[2], -1).map_err(err(\"bd split\"))?;\n        let final_cxcy = bd_parts[0]\n            .multiply(&rb_parts[1])\n            .map_err(err(\"final cxcy mul\"))?\n            .add(&rb_parts[0])\n            .map_err(err(\"final cxcy add\"))?;\n        let final_wh = exp_(&bd_parts[1])?\n            .multiply(&rb_parts[1])\n            .map_err(err(\"final wh mul\"))?;\n        let boxes =\n            ops::concatenate_axis(&[&final_cxcy, &final_wh], -1).map_err(err(\"boxes cat\"))?;\n\n        Ok((boxes, logits))\n    }\n\n    /// Gather slices of `x` along axis 1 by integer indices `idx (B, K)`.\n    /// Result: `(B, K, last_dim)`.\n    fn gather(&self, x: &Array, idx: &Array, last_dim: i32) -> Result<Array> {","sourceCodeStart":660,"sourceCodeEnd":696,"githubUrl":"https://github.com/screenpipe/screenpipe/blob/4ebf712990fee17eeaf904dacf749b6e96ac9bf3/crates/screenpipe-rfdetr-mlx/src/decoder/mod.rs#L660-L696","documentation":"Raised in `forward` when splitting the final `refpoint_embed` (cxcywh boxes) into two halves along the last axis via `ops::split_sections(.., &[2], -1)`. In mlx, a list argument is a set of split indices, so this expects the last dimension to be 4 (split at index 2 into [:, :2] and [:, 2:]). The library throws it when the reference-point tensor's last axis is not 4, making the split index invalid.","triggerScenarios":"Final bbox refinement in `forward` where `refpoint_embed.shape()[-1] != 4` — e.g. a checkpoint whose learned refpoint embedding is (1, 300, 2) or (1, 300, 6), or a tensor that was previously reshaped/transposed incorrectly.","commonSituations":"Loading a DAB/LW-DETR checkpoint variant with a different box parameterization (e.g. xyxy or fewer dims); upstream code change altering refpoint layout; feeding proposal boxes instead of the learned embedding.","solutions":["Assert `refpoint_embed.shape()` is [B, 300, 4] before the split; fix the producer of the tensor if not.","Confirm the checkpoint's `refpoint_embed` weight has shape (300, 4); re-export weights for this model variant if it differs.","If using a cxcywh→xyxy conversion upstream, convert back to cxcywh (or adjust the split sections) before `forward`.","Inspect the wrapped mlx exception for the offending axis size."],"exampleFix":"// before\nlet rb_parts = ops::split_sections(&refpoint_embed, &[2], -1).map_err(err(\"rb split\"))?;\n// after\nassert_eq!(refpoint_embed.shape()[2], 4, \"expected cxcywh (B, 300, 4)\");\nlet rb_parts = ops::split_sections(&refpoint_embed, &[2], -1).map_err(err(\"rb split\"))?;","handlingStrategy":"validation","validationCode":"// Before forward: refpoints must be cxcywh (B, 300, 4)\nlet s = refpoint_embed.shape();\nif s.len() != 3 || s[2] != 4 {\n    return Err(anyhow!(\"refpoint_embed must be (B, 300, 4), got {s:?}\"));\n}","typeGuard":"fn is_cxcywh(a: &mlx_rs::Array) -> bool {\n    a.shape().last().map_or(false, |&d| d == 4)\n}","tryCatchPattern":"match decoder.forward(&enc, &refpoints) {\n    Err(Error::Inference(m)) if m.contains(\"rb split\") => {\n        // convert xyxy -> cxcywh and retry once\n        let cxcywh = xyxy_to_cxcywh(&refpoints)?;\n        decoder.forward(&enc, &cxcywh)\n    }\n    other => other,\n}","preventionTips":["Standardize on cxcywh normalized coordinates at every boundary into the decoder.","Keep the (300, 4) learned refpoint weight untouched when editing export scripts.","Assert last-dim == 4 in unit tests that exercise final box refinement."],"tags":["mlx","shape-mismatch","split","bbox","rust"],"backgroundTag":"mlx-array-split-axis-mismatch","analyzedSha":"4ebf712990fee17eeaf904dacf749b6e96ac9bf3","analyzedAt":"2026-09-01T23:33:43.065Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}