Shopify/liquid · error · Liquid::ZeroDivisionError
e.message (re-raised as Liquid::ZeroDivisionError from…
Error message
e.message (re-raised as Liquid::ZeroDivisionError from ::ZeroDivisionError in modulo)
What it means
The `modulo` filter wraps Ruby's ::ZeroDivisionError and re-raises it as Liquid::ZeroDivisionError. It occurs when the right-hand operand of the modulo operation is 0. Liquid normalizes the native error into its own exception class for template-level handling.
Solutions
- Check the modulus value in the template: `{% if step != 0 %}{{ n | modulo: step }}{% endif %}`.
- Assign a non-zero fallback before the filter: `{% assign step = step | default: 1 %}` (and ensure it is not literal 0).
- Fix upstream data so the modulus count is always a positive integer.
- Rescue Liquid::ZeroDivisionError in the rendering error handler and provide a default result.
- Verify string-to-number coercion: an empty string or nil operand coerces to 0 and triggers the error.
Example fix
// before
{{ index | modulo: step }}
// after
{% if step > 0 %}{{ index | modulo: step }}{% else %}{{ index }}{% endif %} Defensive patterns
Strategy: try-catch
Validate before calling
{% if step and step > 0 %}{{ index | modulo: step }}{% else %}{{ index }}{% endif %} Type guard
def positive_nonzero_int?(v) v.is_a?(Numeric) && v > 0 end
Try / catch
begin template.render(assigns) rescue Liquid::ZeroDivisionError => e default_striping_output end
Prevention
- Guarantee modulus variables are positive integers before render
- Never bind nil/empty values into variables used as moduli
- Rescue Liquid::ZeroDivisionError centrally in the render pipeline
- Test alternating-row/pagination templates with step=0
When it happens
Trigger: Using `{{ 10 | modulo: 0 }}` or `{{ n | modulo: divisor }}` where the divisor variable is 0 or coerces to 0 via Utils.to_number.
Common situations: Alternating-row striping (`cycle`-like logic) or pagination calculations where the modulus count variable is unset, empty, or computed as 0.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- e.message (re-raised as Liquid::ZeroDivisionError from…
- e.message (re-raised as Liquid::FloatDomainError from…
- e.message (re-raised as Liquid::FloatDomainError from…
- e.message (re-raised as Liquid::FloatDomainError from…
- undefined filter #
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/acdb6403449726e8.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/standardfilters.rb:879
# @liquid_syntax number | divided_by: number
# @liquid_return [number]
def divided_by(input, operand)
apply_operation(input, operand, :/)
rescue ::ZeroDivisionError => e
raise Liquid::ZeroDivisionError, e.message
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category math
# @liquid_summary
# Returns the remainder of dividing a number by a given number.
# @liquid_syntax number | modulo: number
# @liquid_return [number]
def modulo(input, operand)
apply_operation(input, operand, :%)
rescue ::ZeroDivisionError => e
raise Liquid::ZeroDivisionError, e.message
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category math
# @liquid_summary
# Rounds a number to the nearest integer.
# @liquid_syntax number | round
# @liquid_return [number]
def round(input, n = 0)
result = Utils.to_number(input).round(Utils.to_number(n))
result = result.to_f if result.is_a?(BigDecimal)
result = result.to_i if n == 0
result
rescue ::FloatDomainError => e
raise Liquid::FloatDomainError, e.message
end
View on GitHub (pinned to 807d45a6b3)