{"record":{"id":"178bea3793c3086b","repo":"huggingface/candle","slug":"trilu-expects-input-with-at-least-2-dimensions","errorCode":null,"errorMessage":"Trilu expects input with at least 2 dimensions: {:?}","messagePattern":"Trilu expects input with at least 2 dimensions: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"candle-onnx/src/eval.rs","lineNumber":2386,"sourceCode":"                values.insert(node.output[0].clone(), output);\n            }\n            \"Trilu\" => {\n                let input = get(&node.input[0])?;\n\n                // Get the diagonal offset 'k' from the second input if provided\n                let k = if node.input.len() > 1 && !node.input[1].is_empty() {\n                    to_vec0_flexible::<i64>(get(&node.input[1])?)?\n                } else {\n                    0\n                };\n\n                // Get the 'upper' attribute\n                let upper = get_attr_opt::<i64>(node, \"upper\")?.copied().unwrap_or(1);\n\n                // For batched inputs, we need to handle each matrix separately\n                let dims = input.dims();\n                if dims.len() < 2 {\n                    bail!(\"Trilu expects input with at least 2 dimensions: {:?}\", dims);\n                }\n\n                // Get the last two dimensions which represent the matrix\n                let n = dims[dims.len() - 2];\n                let m = dims[dims.len() - 1];\n                let max_dim = std::cmp::max(n, m);\n\n                // Handle the diagonal offset k\n                let mask = if k != 0 {\n                    let mut data = vec![0u32; n * m];\n                    for i in 0..n {\n                        for j in 0..m {\n                            if (upper != 0 && (j as i64) >= (i as i64) + k)\n                                || (upper == 0 && (j as i64) <= (i as i64) + k)\n                            {\n                                data[i * m + j] = 1u32;\n                            }\n                        }","sourceCodeStart":2368,"sourceCodeEnd":2404,"githubUrl":"https://github.com/huggingface/candle/blob/d5fee525bfde3273eb7c9b75fd2bc4937be867ca/candle-onnx/src/eval.rs#L2368-L2404","documentation":"The Trilu operator (upper/lower triangular extraction) operates on matrices, so its input must have at least 2 dimensions — the last two being the matrix shape. candle-onnx validates this and bails if the input tensor rank is below 2, since there is no matrix to triangularize.","triggerScenarios":"Feeding a 0-d or 1-d tensor to a Trilu node, e.g. a graph that reshapes/squeezes data before Trilu leaving a [N] tensor.","commonSituations":"Malformed or badly exported graphs (attention mask construction, causal-mask builders) where an unsqueeze was lost; hand-crafted ONNX models.","solutions":["Add a reshape/unsqueeze before the Trilu node so input is at least 2-D","Fix the exporting code to keep the matrix dimensions","Validate input ranks in the graph before running inference"],"exampleFix":"# before: Trilu input shape [N]\n# after\nx = x.reshape((1, N))  # or Unsqueeze with axes=[0] before Trilu","handlingStrategy":"type-guard","validationCode":"let dims = input.dims();\nif dims.len() < 2 {\n    return Err(format!(\"Trilu input rank {} < 2\", dims.len()));\n}","typeGuard":"fn is_matrix_like(t: &Tensor) -> bool { t.rank() >= 2 }","tryCatchPattern":"match eval(...) {\n    Err(e) if e.contains(\"Trilu expects input\") => unsqueeze_and_retry(input),\n    other => other,\n}","preventionTips":["Check tensor ranks feeding Trilu at export time","Keep an explicit unsqueeze before Trilu in graphs","Run onnx.shape_inference to catch rank issues early"],"tags":["onnx","trilu","shape"],"backgroundTag":"invalid-tensor-shape","analyzedSha":"d5fee525bfde3273eb7c9b75fd2bc4937be867ca","analyzedAt":"2026-09-02T00:15:47.023Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}