{"record":{"id":"b7887dfbd83e3186","repo":"ruby-grape/grape","slug":"min-min-cannot-be-greater-than-max-max","errorCode":null,"errorMessage":"min #{@min} cannot be greater than max #{@max}","messagePattern":"min #(.+?) cannot be greater than max #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/grape/validations/validators/length_validator.rb","lineNumber":13,"sourceCode":"# frozen_string_literal: true\n\nmodule Grape\n  module Validations\n    module Validators\n      class LengthValidator < Base\n        def initialize(attrs, options, required, scope, opts)\n          super\n\n          @min, @max, @is = options.values_at(:min, :max, :is)\n          validate_boundary!(:min, @min)\n          validate_boundary!(:max, @max)\n          raise ArgumentError, \"min #{@min} cannot be greater than max #{@max}\" if @min && @max && @min > @max\n\n          return if @is.nil?\n          raise ArgumentError, 'is must be an integer greater than zero' unless @is.is_a?(Integer) && @is.positive?\n          raise ArgumentError, 'is cannot be combined with min or max' unless @min.nil? && @max.nil?\n        end\n\n        def validate_param!(attr_name, params)\n          return unless hash_like?(params)\n\n          param = params[attr_name]\n\n          return unless param.respond_to?(:length)\n\n          return unless (!@min.nil? && param.length < @min) || (!@max.nil? && param.length > @max) || (!@is.nil? && param.length != @is)\n\n          validation_error!(attr_name, message do\n            if @min && @max\n              translate(:length, min: @min, max: @max)","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/ruby-grape/grape/blob/22d7975629846a3c0c7bd2b34e140a7a1b4af8f6/lib/grape/validations/validators/length_validator.rb#L1-L31","documentation":"Grape's `length` validator constrains a param's length with `min:`/`max:`/`is:`. Bounds are validated when the API class is defined: a pair where `min` is greater than `max` describes an empty range — every incoming value would fail — so Grape raises ArgumentError immediately instead of at request time.","triggerScenarios":"`requires :name, length: { min: 10, max: 5 }`; bounds sourced from config/env where MAX drifts below MIN in some environment; constants swapped during a refactor.","commonSituations":"Environment-specific YAML config feeding min and max; copy-paste of another param's length options with only one number updated.","solutions":["Fix the pair so `min <= max`","When bounds come from config, validate them at boot (`raise 'bad config' unless min <= max`) so the failure is attributed to configuration, not the DSL","Derive both ends from one Range constant to keep them consistent: `RANGE = 2..8` then `length: { min: RANGE.min, max: RANGE.max }`"],"exampleFix":"# before\nrequires :name, type: String, length: { min: 10, max: 5 }\n\n# after\nrequires :name, type: String, length: { min: 5, max: 10 }","handlingStrategy":"validation","validationCode":"def valid_length_bounds?(length_opts)\n  min, max = length_opts.values_at(:min, :max)\n  min.nil? || max.nil? || min <= max\nend\n\nraise 'length min exceeds max' unless valid_length_bounds?(cfg[:length])","typeGuard":null,"tryCatchPattern":"begin\n  requires :name, type: String, length: length_cfg\nrescue ArgumentError => e\n  raise \"length bounds from config are inverted: #{e.message}\"\nend","preventionTips":["Validate config-sourced min/max at boot so inversions are blamed on config, not the DSL","Derive both bounds from one Range constant","Review length options when copy-pasting between params"],"tags":["grape","params","length-validation","range","argumenterror"],"backgroundTag":"min-greater-than-max","analyzedSha":"22d7975629846a3c0c7bd2b34e140a7a1b4af8f6","analyzedAt":"2026-08-21T17:03:54.627Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}