{"record":{"id":"f93d5d53830b302d","repo":"usememos/memos","slug":"division-by-zero","errorCode":null,"errorMessage":"division by zero","messagePattern":"division by zero","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"internal/filter/parser.go","lineNumber":573,"sourceCode":"\t\t\treturn 0, false, nil\n\t\t}\n\t\tright, ok, err := evaluateNumeric(call.Args[1], now)\n\t\tif err != nil {\n\t\t\treturn 0, false, err\n\t\t}\n\t\tif !ok {\n\t\t\treturn 0, false, nil\n\t\t}\n\t\tswitch call.Function {\n\t\tcase \"_+_\":\n\t\t\treturn left + right, true, nil\n\t\tcase \"_-_\":\n\t\t\treturn left - right, true, nil\n\t\tcase \"_*_\":\n\t\t\treturn left * right, true, nil\n\t\tcase \"_/_\":\n\t\t\tif right == 0 {\n\t\t\t\treturn 0, false, errors.New(\"division by zero\")\n\t\t\t}\n\t\t\treturn left / right, true, nil\n\t\tcase \"_%_\":\n\t\t\tif right == 0 {\n\t\t\t\treturn 0, false, errors.New(\"modulo by zero\")\n\t\t\t}\n\t\t\treturn left % right, true, nil\n\t\tdefault:\n\t\t\treturn 0, false, errors.Errorf(\"unsupported arithmetic operator %q\", call.Function)\n\t\t}\n\tdefault:\n\t\treturn 0, false, nil\n\t}\n}\n\n// evaluateTimestamp folds timestamp(\"RFC3339\") and timestamp(<epoch int>) into\n// Unix epoch seconds.\nfunc evaluateTimestamp(call *exprv1.Expr_Call) (int64, bool, error) {","sourceCodeStart":555,"sourceCodeEnd":591,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/internal/filter/parser.go#L555-L591","documentation":"During constant folding of division, the right operand evaluated to zero. Because the fold happens at compile time, the filter is rejected before execution; there is no SQL NULL/Infinity escape hatch for integer division by zero in this DSL.","triggerScenarios":"Filters like created_ts > timestamp(\"2024-01-01T00:00:00Z\") / 0 or visibility == 10 / 0 where both sides fold to constants and the divisor is 0. Also duration(\"0h\") used as a divisor: now - duration(\"0h\") style expressions where a zero folds into '_/_'.","commonSituations":"Generated filters that compute a divisor from configuration (page size, divisor constant) that can be zero; copy-pasted arithmetic where the denominator was meant to be a field, not a literal.","solutions":["Remove or fix the division so the constant divisor is non-zero","Guard divisor-producing config values in the calling code before embedding them","Use multiplication instead when the divisor is meant to scale"],"exampleFix":"// before\ncreated_ts > timestamp(\"2024-01-01T00:00:00Z\") / 0\n\n// after\ncreated_ts > timestamp(\"2024-01-01T00:00:00Z\")","handlingStrategy":"validation","validationCode":"// TS: reject zero divisors in generated filters\nconst divisor = Number(cfg.divisor);\nif (!Number.isFinite(divisor) || divisor === 0) {\n  throw new Error('divisor must be a non-zero number');\n}\nconst filter = `created_ts > ${ts} / ${divisor}`;","typeGuard":"const isNonZeroNumber = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v) && v !== 0;","tryCatchPattern":"try { compile(filter); } catch (e) { if (String(e).includes('division by zero')) { filter = filter.replace(/\\/\\s*0(?![.0-9])/g, ''); compile(filter); } else throw e; }","preventionTips":["Validate numeric config values used as divisors before templating","Avoid division in filters when multiplication can express the same scale","Unit-test generated filters with boundary (zero) parameter values"],"tags":["cel","arithmetic","division-by-zero","filter"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}