{"record":{"id":"3854cbff4f185ddc","repo":"Shopify/liquid","slug":"e-message-re-raised-as-liquid-floatdomainerror-f-3854cb","errorCode":null,"errorMessage":"e.message (re-raised as Liquid::FloatDomainError from ::FloatDomainError in ceil)","messagePattern":"e\\.message \\(re-raised as Liquid::FloatDomainError from ::FloatDomainError in ceil\\)","errorType":"exception","errorClass":"Liquid::FloatDomainError","httpStatus":null,"severity":"error","filePath":"lib/liquid/standardfilters.rb","lineNumber":908,"sourceCode":"      result = Utils.to_number(input).round(Utils.to_number(n))\n      result = result.to_f if result.is_a?(BigDecimal)\n      result = result.to_i if n == 0\n      result\n    rescue ::FloatDomainError => e\n      raise Liquid::FloatDomainError, e.message\n    end\n\n    # @liquid_public_docs\n    # @liquid_type filter\n    # @liquid_category math\n    # @liquid_summary\n    #   Rounds a number up to the nearest integer.\n    # @liquid_syntax number | ceil\n    # @liquid_return [number]\n    def ceil(input)\n      Utils.to_number(input).ceil.to_i\n    rescue ::FloatDomainError => e\n      raise Liquid::FloatDomainError, e.message\n    end\n\n    # @liquid_public_docs\n    # @liquid_type filter\n    # @liquid_category math\n    # @liquid_summary\n    #   Rounds a number down to the nearest integer.\n    # @liquid_syntax number | floor\n    # @liquid_return [number]\n    def floor(input)\n      Utils.to_number(input).floor.to_i\n    rescue ::FloatDomainError => e\n      raise Liquid::FloatDomainError, e.message\n    end\n\n    # @liquid_public_docs\n    # @liquid_type filter\n    # @liquid_category math","sourceCodeStart":890,"sourceCodeEnd":926,"githubUrl":"https://github.com/Shopify/liquid/blob/807d45a6b3d4568e64e86b375e3702df2c7c860c/lib/liquid/standardfilters.rb#L890-L926","documentation":"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.","triggerScenarios":"`{{ value | ceil }}` where value coerces to Float::INFINITY or Float::NAN, typically after a prior `divided_by: 0.0` in the same pipeline.","commonSituations":"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.","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."],"exampleFix":"// before\n{% assign pages = total | divided_by: per_page | ceil %}\n// after\n{% if per_page > 0 %}{% assign pages = total | divided_by: per_page | ceil %}{% else %}{% assign pages = 1 %}{% endif %}","handlingStrategy":"validation","validationCode":"# before render\nraise \"non-finite input for ceil\" unless input.nil? || input.to_f.finite?","typeGuard":"def ceil_safe(v)\n  v.is_a?(Numeric) && v.to_f.finite? ? v.to_f.ceil : 0\nend","tryCatchPattern":"begin\n  template.render(assigns)\nrescue Liquid::FloatDomainError => e\n  output_default_page_count\nend","preventionTips":["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"],"tags":["liquid","math","float","infinity","template"],"backgroundTag":"value-out-of-range","analyzedSha":"807d45a6b3d4568e64e86b375e3702df2c7c860c","analyzedAt":"2026-09-08T11:31:38.917Z","contentChangedAt":"2026-09-08T11:31:38.917Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}