{"record":{"id":"a62ae9ff97c24e87","repo":"tursodatabase/turso","slug":"group-concat-accumulator-must-be-a-text-value","errorCode":null,"errorMessage":"group_concat accumulator must be a Text value","messagePattern":"group_concat accumulator must be a Text value","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/vdbe/value.rs","lineNumber":1420,"sourceCode":"                return Value::Null;\n            }\n            result = Some(match result {\n                None => v,\n                Some(cur) if v > cur => v,\n                Some(cur) => cur,\n            });\n        }\n        result.map(|v| v.to_owned()).unwrap_or(Value::Null)\n    }\n\n    /// Fallibly concatenate another value onto this Text value, converting it to a string.\n    /// Panics if self is not a Text value.\n    pub fn exec_group_concat(\n        &mut self,\n        other: &Value,\n    ) -> std::result::Result<(), crate::alloc::TryReserveError> {\n        let Value::Text(text) = self else {\n            panic!(\"group_concat accumulator must be a Text value\");\n        };\n        let acc = match &mut text.value {\n            std::borrow::Cow::Owned(s) => s,\n            borrowed => {\n                let mut s = String::new();\n                s.try_reserve(borrowed.len())?;\n                s.push_str(borrowed);\n                *borrowed = std::borrow::Cow::Owned(s);\n                let std::borrow::Cow::Owned(s) = borrowed else {\n                    unreachable!(\"accumulator was just converted to Owned\");\n                };\n                s\n            }\n        };\n        match other {\n            Value::Text(text) => {\n                acc.try_reserve(text.as_str().len())?;\n                acc.push_str(text.as_str());","sourceCodeStart":1402,"sourceCodeEnd":1438,"githubUrl":"https://github.com/tursodatabase/turso/blob/492c4a71cd7c2649e7df83da1471b74f4b1c7aa9/core/vdbe/value.rs#L1402-L1438","documentation":"Value::exec_group_concat() appends a row's value to the group accumulator and requires the accumulator to already be Value::Text — SQLite seeds group_concat's accumulator with an empty string before the first step. The panic means the accumulator held a non-Text value (Null, Integer, ...) when the next row was concatenated: the aggregate's initial value was never set up, or the accumulator register was clobbered or reused by other bytecode.","triggerScenarios":"SELECT group_concat(x [, sep]) where the seeded '' accumulator is lost before AggStep runs — e.g. combined with DISTINCT, ORDER BY inside group_concat, FILTER clauses, or window-function variants that re-initialize accumulators; also after changes to aggregate initialization in translate/.","commonSituations":"group_concat with ORDER BY or DISTINCT modifiers; aggregates in trigger or co-routine contexts; engine upgrades altering accumulator setup.","solutions":["Report the exact group_concat call shape — the accumulator must be seeded Text '' before the first step","Drop ORDER BY / DISTINCT / FILTER modifiers on group_concat to use the plain path","Compute the concatenation in its own GROUP BY subquery level","Upgrade"],"exampleFix":"-- before\nSELECT group_concat(v ORDER BY k) FROM t;\n\n-- after (plain form)\nSELECT group_concat(v) FROM t;","handlingStrategy":"type-guard","validationCode":"// before appending a row, confirm the accumulator is seeded Text\nif !matches!(accumulator, Value::Text(_)) {\n    let seeded = Value::Text(String::new().into()); // SQLite seeds '' before the first step\n}","typeGuard":"fn text_accumulator(v: &Value) -> bool {\n    matches!(v, Value::Text(_))\n}","tryCatchPattern":null,"preventionTips":["Cover group_concat with DISTINCT/ORDER BY/FILTER in the aggregate test suite","Ensure accumulator registers are seeded before the first AggStep in new aggregate codegen","Report the exact call shape; the engine must seed the accumulator itself"],"tags":["vdbe","aggregate","group-concat","registers","panic","runtime"],"backgroundTag":"aggregate-accumulator-type-error","analyzedSha":"492c4a71cd7c2649e7df83da1471b74f4b1c7aa9","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}