{"record":{"id":"841f89a8f3223b5d","repo":"dgraph-io/dgraph","slug":"division-by-zero","errorCode":null,"errorMessage":"Division by zero","messagePattern":"Division by zero","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dql/math.go","lineNumber":117,"sourceCode":"\treturn false\n}\n\nfunc evalMathStack(opStack, valueStack *mathTreeStack) error {\n\ttopOp, err := opStack.pop()\n\tif err != nil {\n\t\treturn errors.Errorf(\"Invalid Math expression\")\n\t}\n\tswitch {\n\tcase isUnary(topOp.Fn):\n\t\t// Since \"not\" is a unary operator, just pop one value.\n\t\ttopVal, err := valueStack.pop()\n\t\tif err != nil {\n\t\t\treturn errors.Errorf(\"Invalid math statement. Expected 1 operands\")\n\t\t}\n\t\tif opStack.size() > 1 {\n\t\t\tpeek := opStack.peek().Fn\n\t\t\tif (peek == \"/\" || peek == \"%\") && isZero(topOp.Fn, topVal.Const) {\n\t\t\t\treturn errors.Errorf(\"Division by zero\")\n\t\t\t}\n\t\t}\n\t\ttopOp.Child = []*MathTree{topVal}\n\n\tcase isTernary(topOp.Fn):\n\t\tif valueStack.size() < 3 {\n\t\t\treturn errors.Errorf(\"Invalid Math expression. Expected 3 operands\")\n\t\t}\n\t\ttopVal1 := valueStack.popAssert()\n\t\ttopVal2 := valueStack.popAssert()\n\t\ttopVal3 := valueStack.popAssert()\n\t\ttopOp.Child = []*MathTree{topVal3, topVal2, topVal1}\n\n\tdefault:\n\t\tif valueStack.size() < 2 {\n\t\t\treturn errors.Errorf(\"Invalid Math expression. Expected 2 operands\")\n\t\t}\n\t\tif isZero(topOp.Fn, valueStack.peek().Const) {","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/dql/math.go#L99-L135","documentation":"The math parser detects division (or modulo) by a constant zero operand and rejects the query before evaluation. In the unary branch this fires when a '/' or '%' operator sits on the operator stack above a unary op whose operand constant is zero. DQL math is evaluated per-node and constant zero divisors are statically detected.","triggerScenarios":"Expressions like math(a / 0) or math(a % 0), or unary results known to be zero feeding a division, e.g. math(a / floor(0.5)) since floor(0.5) == 0.","commonSituations":"Hardcoded 0 divisor left in query from templating; computing a divisor with floor/ceil that lands on 0 for some values; math(a / since(u)) where since can be 0 for fresh nodes.","solutions":["Guard the divisor: use cond(a != 0, a / b, 0) style ternary, or filter out zero-divisor values first.","Replace literal 0 divisors with a real value or sentinel like 1.","Use val() variables computed with max(divisor, 1) style logic (math(max(d,1)) as safe_d) before dividing.","Reorder computation so the divisor is never the constant zero."],"exampleFix":"// before\nd as math(count / 0)\n// after\nd as math(cond(divisor == 0, 0, count / divisor))","handlingStrategy":"validation","validationCode":"// Reject constant-zero divisors before sending\nfunction hasZeroDivisor(expr) {\n  return /\\/\\s*0(\\.0+)?\\b/.test(expr) || /%\\s*0(\\.0+)?\\b/.test(expr);\n}\nif (hasZeroDivisor('a / 0')) throw new Error('Constant zero divisor in math expression');","typeGuard":null,"tryCatchPattern":"try {\n  return await dgraph.query(query);\n} catch (err) {\n  if (/Division by zero\\.?$/.test(String(err).trim())) {\n    throw new Error('Replace zero divisors with cond-guarded division: cond(d == 0, 0, a / d)');\n  }\n  throw err;\n}","preventionTips":["Never hardcode 0 as a divisor in DQL math","Use cond(a, b, c) ternary to guard divisions","Compute divisors via variables and clamp them away from zero","Review template-generated queries for injected zero divisors"],"tags":["dql","dgraph","division-by-zero","math"],"backgroundTag":"division-by-zero","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}