← Back to Issue

Fix LengthValidator crash with proc minimum and nil value

From uloza+hey@proton.me · original ↗ · unsubscribe

The proc was resolved only when the value was present, so for a nil value it leaked unresolved into the error message and was invoked with the message options hash instead of the record. It is now resolved before the error is built, producing the expected “is too short” message.


Fix LengthValidator crash with proc minimum and nil value by ousamabenyounes · Pull Request #58428 · rails/rails · GitHub

Skip to content

Sign in

Appearance settings

Search/

Sign in

Sign up

Appearance settings

You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session. Dismiss alert

Uh oh!

There was an error while loading. Please reload this page.

rails / rails Public

Additional navigation options

Fix LengthValidator crash with proc minimum and nil value - #58428

#58428

Merged

kamipo merged 1 commit into

rails:mainrails/rails:mainfrom

ousamabenyounes:fix/issue-40642ousamabenyounes/rails:fix/issue-40642Copy head branch name to clipboard

Aug 10, 2026

ConversationCommits1 (1)ChecksFiles changed

Merged

##

Fix LengthValidator crash with proc minimum and nil value#58428

kamipo merged 1 commit into

rails:mainrails/rails:mainfrom

ousamabenyounes:fix/issue-40642ousamabenyounes/rails:fix/issue-40642Copy head branch name to clipboard

Conversation

@ousamabenyounes

###

@ousamabenyounesousamabenyounes commented Aug 10, 2026

Copy link

Copy Markdown

Contributor

Motivation / Background

Fixes #40642.

LengthValidator raises NoMethodError when a :minimum (or :is) length
constraint is given as a proc and the validated value is nil:

class Foo include ActiveModel::Validations validates :bar, length: { minimum: ->(record) { record.one + 2 } } def one = 1 def bar = nil end

Foo.new.errors.messages # => NoMethodError: undefined method ‘one’ for an instance of Hash

The proc was resolved (resolve_value) only inside the branch guarded by the
value being present:

if !value.nil? || skip_nil_check?(key) check_value = resolve_value(record, check_value) … end errors_options[:count] = check_value

skip_nil_check? is only true for :maximum, so for a nil value with a
:minimum/:is proc the branch is skipped and the raw proc is stored in
errors_options[:count]. It then leaks into I18n interpolation and is invoked
with the message options hash instead of the record, raising NoMethodError.

Detail

Resolve the check value once, before the error is built, so :count is always
a concrete value. Currently-working paths are unchanged: resolve_value is
idempotent for concrete integers, and the proc is still invoked exactly once
per check. (Symbols were already resolved correctly downstream and are not
affected.)

     CHECKS.each do |key, validity\_check|
       next unless check\_value = options\[key\]
  • check_value = resolve_value(record, check_value) + if !value.nil? || skip_nil_check?(key) - check_value = resolve_value(record, check_value) next if value_length.public_send(validity_check, check_value) end

Additional information

Test verification (RED → GREEN)

Two regression tests were added (proc as :minimum and as :is, both with a
nil value).

RED — activemodel/lib/active_model/validations/length.rb at its unmodified
main state, with only the new tests applied:

Error:
LengthValidationTest#test_validates_length_of_using_proc_as_minimum_with_nil_value:
NoMethodError: undefined method 'min_title_length' for an instance of Hash
Error:
LengthValidationTest#test_validates_length_of_using_proc_as_is_with_nil_value:
NoMethodError: undefined method 'exact_title_length' for an instance of Hash
43 runs, 295 assertions, 0 failures, 2 errors, 0 skips

GREEN — with the fix applied (full Active Model suite):

1197 runs, 5378 assertions, 0 failures, 0 errors, 0 skips

Checklist

  • This Pull Request is related to one change.
  • Commit message has a detailed description of what changed and why.
  • Tests are added or updated if you fix a bug or add a feature.
  • CHANGELOG files are updated for the changed libraries if there is a behavior change or additional feature.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions@ousamabenyounes

[Fix LengthValidator crash with proc minimum and nil value](/rails/rails/pull/58428/commits/9096675dffaa225b2a321658d17f12b494c191b3 "Fix LengthValidator crash with proc minimum and nil value [Fix #40642] When a length constraint (:minimum or :is) was given as a proc, resolve_value was only called inside the branch guarded by the value being present. For a nil value with a :minimum (or :is) constraint the raw proc leaked unresolved into errors_options[:count] and was later invoked with the message options hash during I18n interpolation, raising NoMethodError instead of producing the expected \"is too short\" message. Resolve the check value once, before building the error, so the error message always receives a concrete count. Currently-working paths are unchanged since resolve_value is idempotent for concrete integers and the proc is still invoked exactly once per check.") …

[9096675](/rails/rails/pull/58428/commits/9096675dffaa225b2a321658d17f12b494c191b3)

[Fix rails#40642]

When a length constraint (:minimum or :is) was given as a proc, resolve_value was only called inside the branch guarded by the value being present. For a nil value with a :minimum (or :is) constraint the raw proc leaked unresolved into errors_options[:count] and was later invoked with the message options hash during I18n interpolation, raising NoMethodError instead of producing the expected “is too short” message.

Resolve the check value once, before building the error, so the error message always receives a concrete count. Currently-working paths are unchanged since resolve_value is idempotent for concrete integers and the proc is still invoked exactly once per check.

@github-actions github-actions Bot added the activemodel label Aug 10, 2026

Hide details View details

@kamipo

kamipo merged commit e137505 into rails:main Aug 10, 2026

5 checks passed

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

### Reviewers

No reviews

Assignees

No one assigned

Labels

activemodel

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

LenthValidator breaks if nil value has a minimum length with a proc.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@ousamabenyounes@kamipo

Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

© 2026 GitHub, Inc.

You can’t perform that action at this time.

Highlights & notes

    Notes