{"record":{"id":"d5f350b0c148753b","repo":"dgraph-io/dgraph","slug":"only-aggregated-variables-allowed-within-empty-blo","errorCode":null,"errorMessage":"Only aggregated variables allowed within empty block.","messagePattern":"Only aggregated variables allowed within empty block\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"query/outputnode.go","lineNumber":1045,"sourceCode":"\t\t\t}\n\t\t}\n\t\tfor _, it := range grp.aggregates {\n\t\t\tif err := enc.AddValue(uc, enc.idForAttr(it.attr), it.key); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\tenc.AddListChild(g, uc)\n\t}\n\tenc.AddListChild(fj, g)\n\treturn nil\n}\n\nfunc (sg *SubGraph) addAggregations(enc *encoder, fj fastJsonNode) error {\n\tfor _, child := range sg.Children {\n\t\taggVal, ok := child.Params.UidToVal.Get(0)\n\t\tif !ok {\n\t\t\tif len(child.Params.NeedsVar) == 0 {\n\t\t\t\treturn errors.Errorf(\"Only aggregated variables allowed within empty block.\")\n\t\t\t}\n\t\t\t// the aggregation didn't happen, most likely was called with unset vars.\n\t\t\t// See: query.go:fillVars\n\t\t\t// In this case we do nothing. The aggregate value in response will be returned as NULL.\n\t\t}\n\t\tif child.Params.Normalize && child.Params.Alias == \"\" {\n\t\t\tcontinue\n\t\t}\n\t\tfieldName := child.aggWithVarFieldName()\n\t\tn1 := enc.newNode(enc.idForAttr(sg.Params.Alias))\n\t\tif err := enc.AddValue(n1, enc.idForAttr(fieldName), aggVal); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tenc.AddListChild(fj, n1)\n\t}\n\tif enc.IsEmpty(fj) {\n\t\tenc.AddListChild(fj, enc.newNode(enc.idForAttr(sg.Params.Alias)))\n\t}","sourceCodeStart":1027,"sourceCodeEnd":1063,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/query/outputnode.go#L1027-L1063","documentation":"When a sub-block of a query yields no UIDs, Dgraph still tries to surface its aggregated variables. If the aggregation block is empty AND it has no tracked input variables (NeedsVar empty), there is no aggregation value to encode — the query only contained non-aggregation content in an empty block, which is invalid.","triggerScenarios":"A query block that matches zero nodes containing a math/aggregate variable whose source variables were never set or matched nothing, so UidToVal.Get(0) fails and child.Params.NeedsVar is empty during addAggregations (called from processNodeUids).","commonSituations":"Aggregate inside a block filtered to zero results where the var was declared with the wrong name or the filter excludes everything; typos in variable names so fillVars never populates them; @groupby/math blocks under empty parent UIDs.","solutions":["Fix the variable name/declaration so the aggregation references a var actually produced by an earlier block","Loosen or correct the filter that empties the block so it matches nodes","Ensure aggregate(math(...)) blocks reference grouped/source variables (aggregations require an input var)","Check query.go fillVars path: confirm the upstream block that should set the var actually executes before this block"],"exampleFix":"// before\n{\n  var(func: has(score)) @filter(gt(score, 100)) {\n    s as score\n  }\n  q(func: uid(0)) {\n    total as sum(val(s))\n  }\n}\n// after: guard for empty result or fix filter\n{\n  var(func: has(score)) {\n    s as score\n  }\n  q(func: uid(0)) {\n    total as sum(val(s))\n  }\n}","handlingStrategy":"validation","validationCode":"// verify the source block matches before running the aggregation query\nconst probe = await dgraph.query('{ p(func: has(score)) @filter(gt(score, 100)) { uid } }');\nif (!probe.p.length) throw new Error('aggregation source block is empty; fix filter/vars first');","typeGuard":null,"tryCatchPattern":"try {\n  return await dgraph.query(q);\n} catch (e) {\n  if (String(e).includes('Only aggregated variables allowed within empty block')) {\n    // treat as empty aggregate: return 0/null, or retry with corrected variable names\n  }\n  throw e;\n}","preventionTips":["Ensure every aggregate(math(...)) references a var bound by an earlier block","Double-check variable names for typos (var 's' vs 'as s')","Probe filters with a count query before aggregations","Keep aggregation variables and their sources in the same query path"],"tags":["dgraph","query","aggregation","empty-result"],"backgroundTag":"aggregation-on-empty-block","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}