{"record":{"id":"d8b3fde657159fe4","repo":"xai-org/x-algorithm","slug":"not-structarray","errorCode":null,"errorMessage":"not StructArray","messagePattern":"not StructArray","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"bdsm/rust/abuse-v3-features/src/lib.rs","lineNumber":273,"sourceCode":"        arrow::compute::concat_batches(&batches[0].schema(), &batches)?\n    };\n\n    let actions_col = batch\n        .column_by_name(\"user_actions\")\n        .ok_or_else(|| anyhow::anyhow!(\"no user_actions\"))?;\n    let list = actions_col\n        .as_any()\n        .downcast_ref::<ListArray>()\n        .ok_or_else(|| anyhow::anyhow!(\"not ListArray\"))?;\n    if list.is_empty() || list.is_null(0) {\n        anyhow::bail!(\"empty list\");\n    }\n\n    let vals = list.value(0);\n    let sa = vals\n        .as_any()\n        .downcast_ref::<StructArray>()\n        .ok_or_else(|| anyhow::anyhow!(\"not StructArray\"))?;\n    let total = sa.len();\n    if total == 0 {\n        anyhow::bail!(\"zero actions\");\n    }\n\n    let start = if total > seq_len { total - seq_len } else { 0 };\n    let take = total.min(seq_len);\n    let sl = sa.slice(start, take);\n    let sl = sl.as_any().downcast_ref::<StructArray>().unwrap();\n    let n = take;\n\n    Ok(UserArrowFeatures {\n        n,\n        action_name: get_i32(sl, \"action_name\"),\n        tweet_id: get_i64(sl, \"tweet_id\"),\n        author_id: get_i64(sl, \"author_id\"),\n        engagement_time_ms: get_i64(sl, \"engagement_time_ms\"),\n        dwell_time: get_i32(sl, \"dwell_time\"),","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/xai-org/x-algorithm/blob/24c60942c5c5fdad3a6addffb4c6e6d2f228f04f/bdsm/rust/abuse-v3-features/src/lib.rs#L255-L291","documentation":"The elements of the user_actions list must be a StructArray (each action a struct with feature fields). After taking list.value(0), the code downcasts to StructArray; if the list's value type is not a struct (e.g. primitives or a nested list), this error is raised. It also guards against a 'zero actions' bail immediately after.","triggerScenarios":"Calling extract_batch where the list's inner type is not Struct — producer changed the element type, or the actions structs were flattened/unnested upstream.","commonSituations":"Schema evolution of the action struct (fields added/removed and re-encoded differently), producers writing list<list<...>> or list<string> variants, or mismatched versions between the feature-generation job and this library.","solutions":["Inspect list.value_type() / the inner DataType and compare against the expected struct fields","Fix the producer to emit list<struct<...>> with the agreed field set","Update this consumer to handle the new inner type if the change is intentional","Add a schema contract check (expected inner struct fields) before extraction runs"],"exampleFix":"// before\nlet sa = vals\n    .as_any()\n    .downcast_ref::<StructArray>()\n    .ok_or_else(|| anyhow::anyhow!(\"not StructArray\"))?;\n\n// after\nlet sa = vals\n    .as_any()\n    .downcast_ref::<StructArray>()\n    .ok_or_else(|| anyhow::anyhow!(\n        \"not StructArray: inner type is {:?}\",\n        vals.data_type()\n    ))?;","handlingStrategy":"type-guard","validationCode":"// Validate inner element type before extraction\nif let Some(col) = batch.column_by_name(\"user_actions\") {\n    if let DataType::List(f) = col.data_type() {\n        anyhow::ensure!(matches!(f.data_type(), DataType::Struct(_)), \"inner type must be struct\");\n    }\n}","typeGuard":"fn actions_are_structs(list: &ListArray) -> bool {\n    matches!(list.value_type(), DataType::Struct(_))\n}","tryCatchPattern":"// verify inner type, then downcast safely\nlet vals = list.value(0);\nlet sa = vals.as_any().downcast_ref::<StructArray>()\n    .ok_or_else(|| anyhow::anyhow!(\"expected struct inner type, got {:?}\", vals.data_type()))?;","preventionTips":["Share the exact struct field definitions between producer and consumer","Add schema contract tests that run the extractor against a golden batch","Fail fast on schema changes in CI with a schema-diff check"],"tags":["rust","arrow","downcast","struct-array","type-mismatch"],"backgroundTag":"type-downcast-failed","analyzedSha":"24c60942c5c5fdad3a6addffb4c6e6d2f228f04f","analyzedAt":"2026-08-28T11:40:14.686Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}