Shopify/liquid · error · Liquid::FloatDomainError
e.message (re-raised as Liquid::FloatDomainError from…
Error message
e.message (re-raised as Liquid::FloatDomainError from ::FloatDomainError in ceil)
What it means
The `ceil` filter wraps Ruby's ::FloatDomainError and re-raises it as Liquid::FloatDomainError. It is raised when the input number is NaN or Infinity, values with no integer ceiling. Liquid re-raises the native error under its own class for consistent template error handling.
Solutions
- Ensure the divisor feeding any upstream float division is a non-zero integer or validated float.
- Guard the input in the template before applying ceil.
- Rescue Liquid::FloatDomainError in the error renderer and output a sensible default (e.g. 1 page).
- Validate external data: reject Infinity/NaN from API/JSON payloads before template rendering.
- Add tests covering per_page = 0 and empty totals for pagination templates.
Example fix
// before
{% assign pages = total | divided_by: per_page | ceil %}
// after
{% if per_page > 0 %}{% assign pages = total | divided_by: per_page | ceil %}{% else %}{% assign pages = 1 %}{% endif %} Defensive patterns
Strategy: validation
Validate before calling
# before render raise "non-finite input for ceil" unless input.nil? || input.to_f.finite?
Type guard
def ceil_safe(v) v.is_a?(Numeric) && v.to_f.finite? ? v.to_f.ceil : 0 end
Try / catch
begin template.render(assigns) rescue Liquid::FloatDomainError => e output_default_page_count end
Prevention
- Check pagination denominators (per_page) are non-zero before ceil
- Guard upstream divisions feeding ceil
- Validate numeric fields from external APIs
- Rescue Liquid::FloatDomainError in the render handler
When it happens
Trigger: `{{ value | ceil }}` where value coerces to Float::INFINITY or Float::NAN, typically after a prior `divided_by: 0.0` in the same pipeline.
Common situations: Pagination page counts (`{{ total | divided_by: per_page | ceil }}`) when per_page is 0.0 or a float zero; dashboards computing ceilings of averaged metrics with bad denominators.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- e.message (re-raised as Liquid::FloatDomainError from…
- e.message (re-raised as Liquid::FloatDomainError from…
- e.message (re-raised as Liquid::ZeroDivisionError from…
- e.message (re-raised as Liquid::ZeroDivisionError from…
- undefined filter #
AI-assisted analysis of Shopify/liquid@807d45a6b3 (2026-09-08).
Data as JSON: /api/errors/3854cbff4f185ddc.
Report an issue: GitHub.
Appendix: source
Thrown at lib/liquid/standardfilters.rb:908
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
# @liquid_public_docs
# @liquid_type filter
# @liquid_category math
# @liquid_summary
# Rounds a number up to the nearest integer.
# @liquid_syntax number | ceil
# @liquid_return [number]
def ceil(input)
Utils.to_number(input).ceil.to_i
rescue ::FloatDomainError => e
raise Liquid::FloatDomainError, e.message
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category math
# @liquid_summary
# Rounds a number down to the nearest integer.
# @liquid_syntax number | floor
# @liquid_return [number]
def floor(input)
Utils.to_number(input).floor.to_i
rescue ::FloatDomainError => e
raise Liquid::FloatDomainError, e.message
end
# @liquid_public_docs
# @liquid_type filter
# @liquid_category mathView on GitHub (pinned to 807d45a6b3)