{"record":{"id":"7500c535525acf97","repo":"PRQL/prql","slug":"tuple-expected-to-have-at-least-one-entry-when-in","errorCode":null,"errorMessage":"tuple: expected to have at least one entry when initial value is not provided, found empty tuple","messagePattern":"tuple: expected to have at least one entry when initial value is not provided, found empty tuple","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"prqlc/prqlc/src/semantic/resolver/transforms.rs","lineNumber":357,"sourceCode":"                    found: write_pl(pattern.clone()),\n                })\n                .with_span(pattern.span));\n            }\n\n            \"tuple_reduce\" => {\n                // yes, this is not a transform, but this is the most appropriate place for it\n\n                let [init, func, list] = unpack::<3>(func.args);\n                let list_items = list.kind.into_tuple().unwrap();\n                let num_items = list_items.len();\n                let mut list_iter = list_items.into_iter();\n\n                let mut res = init.clone();\n\n                if let ExprKind::Literal(Literal::String(init_val)) = &init.kind {\n                    if init_val == \"__missing\" {\n                        match num_items {\n                            0 => return Err(Error::new(Reason::Expected {\n                                who: Some(\"tuple\".to_string()),\n                                expected:\n                                    \"to have at least one entry when initial value is not provided\"\n                                        .to_string(),\n                                found: \"empty tuple\".to_string(),\n                            })\n                            .with_span(list.span)\n                            .push_hint(\"try adding an initial:<value> parameter\")),\n                            1 => {\n                                let item = list_iter.next().unwrap();\n                                return Ok(item);\n                            }\n                            _ => {\n                                res = list_iter.next().unwrap();\n                            }\n                        }\n                    }\n                }","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/PRQL/prql/blob/e164e249b99485890036eb60f57c37520379b240/prqlc/prqlc/src/semantic/resolver/transforms.rs#L339-L375","documentation":"PRQL's internal `tuple_reduce` fold lowers to a fold over a tuple (list) of expressions. When no initial value was supplied (signaled internally by the sentinel literal `\"__missing\"`), the tuple must contain at least one element so the first element can seed the fold. An empty tuple with no initial value leaves nothing to accumulate, so the resolver rejects it at compile time.","triggerScenarios":"Writing a PRQL expression that lowers to `tuple_reduce` (e.g. a fold/sum-like aggregate over columns) where the tuple argument expands to zero columns at compile time and no `initial:` parameter is given — e.g. selecting a dynamic column list that resolves to empty, or calling an aggregate with no arguments.","commonSituations":"Aggregations like `aggregate { }` with an empty tuple, or generated PRQL (from ORMs/tools) that emit an aggregate over a column list that ended up empty because a filter removed all columns or a variable interpolated to nothing.","solutions":["Add an explicit initial value, e.g. pass `initial:0` (or the appropriate identity) to the fold/aggregate so the empty tuple is valid.","Check why the tuple is empty: inspect the column list/interpolation feeding the aggregate and ensure at least one column is produced.","Guard in generating code: if the column list is empty, skip the aggregate or emit a constant instead."],"exampleFix":"// before\naggregate { }\n// after\naggregate { total = sum salary }","handlingStrategy":"validation","validationCode":"// before compiling/generating PRQL\nif (columns.length === 0 && initial === undefined) {\n  throw new Error(\"aggregate over empty tuple requires an `initial:` value\");\n}","typeGuard":"const hasInitial = (args) => args.some(a => a.name === 'initial' || a.startsWith('initial:'));","tryCatchPattern":"// prqlc reports this at compile time; catch the compiler output\ntry {\n  compile(prqlSource);\n} catch (e) {\n  if (e.message.includes('at least one entry when initial value is not provided')) {\n    // regenerate query with an explicit initial value\n  }\n}","preventionTips":["Always supply `initial:` when folding over dynamically generated column lists","Assert non-empty column lists before emitting aggregate code in generators","Add a unit test for the empty-columns case in any PRQL-generating tool"],"tags":["prql","compile-time","aggregate","empty-tuple"],"backgroundTag":"empty-required-field","analyzedSha":"e164e249b99485890036eb60f57c37520379b240","analyzedAt":"2026-09-09T12:18:38.727Z","contentChangedAt":"2026-09-09T12:18:38.727Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}