Skip to content

Wrong Index Reported for Unknown Key Errors #743

@xiaoxipang

Description

@xiaoxipang

Describe the bug

When config.validate_keys = true is enabled and an unknown key error occurs at array index ≥ 10, dry-validation reports the error at approximately index / 10 (integer division) instead of the actual index.

To Reproduce

Executable script:

require 'dry-validation'

class TestContract < Dry::Validation::Contract
  config.validate_keys = true

  schema do
    required(:items).array(:hash) do
      required(:name).filled(:string)
      required(:id).filled(:string)
    end
  end
end

# Create 88 items with unknown key at index 69
items = (0...88).map { |i| { name: "item-#{i}", id: "ID-#{i}" } }
items[69][:unknown_key] = 'value'  # Add unknown key at index 69

contract = TestContract.new
result = contract.call({ items: items })

puts "Expected error at index: 69"
puts "Actual error at index:   #{result.errors.first.path[1]}"
puts "Match: #{result.errors.first.path[1] == 69 ? 'PASS ✅' : 'FAIL ❌'}"

# Test the pattern across multiple indices
puts "\nPattern verification:"
[10, 20, 30, 40, 50, 60, 69, 70, 80, 90].each do |idx|
  test_items = (0..idx).map { |i| { name: "item-#{i}", id: "ID-#{i}" } }
  test_items[idx][:unknown] = 'val'

  test_result = TestContract.new.call({ items: test_items })
  reported = test_result.errors.first.path[1]
  expected_if_bug = idx / 10

  puts "  Index #{idx.to_s.rjust(2)}: reported #{reported}, expected #{idx}, matches bug pattern (#{expected_if_bug}): #{reported == expected_if_bug ? 'YES ❌' : 'NO'}"
end

Steps:

  1. Install dry-validation: gem install dry-validation
  2. Save the script above to a file (e.g., test_bug.rb)
  3. Run: ruby test_bug.rb

Expected behavior

The error should be reported at the correct index:

  • Error path: [:items, 69, :unknown_key]
  • Output: "Actual error at index: 69"

Actual behavior

The error is reported at the wrong index:

  • Error path: [:items, 6, :unknown_key] (should be 69, not 6)
  • Output: "Actual error at index: 6"

Pattern observed:

Actual Index Reported Index Pattern
0-9 0-9 ✅ Correct
10-19 1 index / 10
20-29 2 index / 10
30-39 3 index / 10
69 6 index / 10
70-79 7 index / 10
80-89 8 index / 10
90-99 9 index / 10
100+ Wraps around index % 100

My environment

  • Affects my production application: YES (caused debugging confusion - errors were reported for wrong objects)
  • dry-validation version: 1.11.1
  • Ruby version: 3.4.2
  • OS: macOS (Darwin 24.6.0)

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions