{"record":{"id":"722c28b7b2caf184","repo":"dgraph-io/dgraph","slug":"division-by-zero-722c28","errorCode":null,"errorMessage":"Division by zero.","messagePattern":"Division by zero\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dql/math.go","lineNumber":136,"sourceCode":"\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) {\n\t\t\treturn errors.Errorf(\"Division by zero.\")\n\t\t}\n\t\ttopVal1 := valueStack.popAssert()\n\t\ttopVal2 := valueStack.popAssert()\n\t\ttopOp.Child = []*MathTree{topVal2, topVal1}\n\n\t}\n\t// Push the new value (tree) into the valueStack.\n\tvalueStack.push(topOp)\n\treturn nil\n}\n\nfunc isMathFunc(f string) bool {\n\t// While adding an op, also add it to the corresponding function type.\n\treturn f == \"*\" || f == \"%\" || f == \"+\" || f == \"-\" || f == \"/\" ||\n\t\tf == \"exp\" || f == \"ln\" || f == \"cond\" ||\n\t\tf == \"<\" || f == \">\" || f == \">=\" || f == \"<=\" ||\n\t\tf == \"==\" || f == \"!=\" ||\n\t\tf == \"min\" || f == \"max\" || f == \"sqrt\" ||","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/dql/math.go#L118-L154","documentation":"Static zero-divisor check: when evaluating a binary operator, if the top-of-stack (right) operand is a constant equal to 0 and the operator is '/', '%' (or zero is invalid for ceil/sqrt/u- contexts), the parser rejects the query with 'Division by zero.'. Note the trailing period distinguishes it from the unary-branch variant.","triggerScenarios":"math(a / 0), math(a % 0), or the right-hand operand is a zero constant produced by a parsed numeric literal, e.g. math(a / 0.0) or math(a / (1 - 1)).","commonSituations":"Template-generated queries where a variable interpolated to 0; hardcoded placeholder divisor never replaced; computing a constant sub-expression that evaluates to zero like math(count / (len - len)) style constructs.","solutions":["Use cond to guard: math(cond(d == 0, 0, a / d)) — but since this fires on constants, replace the constant 0 with a nonzero value.","Replace the zero constant divisor with a real variable or 1.","Precompute the divisor as a variable and filter zero values before the math block.","Review templating that injects numeric divisors to ensure 0 can never be emitted."],"exampleFix":"// before\ntotal as math(sum / 0)\n// after\navg as math(cond(cnt == 0, 0, sum / cnt))","handlingStrategy":"validation","validationCode":"function assertNoZeroDivisor(expr) {\n  if (/\\/\\s*0+(\\.0+)?\\b/.test(expr) || /%\\s*0+(\\.0+)?\\b/.test(expr)) {\n    throw new Error('math expression divides by constant zero');\n  }\n}\nassertNoZeroDivisor('sum / 0');","typeGuard":null,"tryCatchPattern":"try {\n  return await dgraph.query(query);\n} catch (err) {\n  if (/Division by zero\\.$/.test(String(err))) {\n    throw new Error('Constant zero divisor found; use a nonzero constant or a guarded variable');\n  }\n  throw err;\n}","preventionTips":["Replace placeholder divisors (0) with real values before shipping templates","Use cond to guard any potentially-zero divisor","Interpolate divisor variables with a Math.max(d, 1) clamp","Add a lint rule scanning DQL strings for '/ 0' and '% 0'"],"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-08T10:18:20.063Z"}