# dry-validation: validate\_keys for nested array

**URL:** https://discourse.dry-rb.org/t/dry-validation-validate-keys-for-nested-array/1852
**Category:** Support
**Created:** [October 16, 2024, 4:10pm UTC](https://discourse.dry-rb.org/t/dry-validation-validate-keys-for-nested-array/1852 "2024-10-16T16:10:41Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![dmke](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/dmke/32/951_2.png) [@dmke](https://discourse.dry-rb.org/u/dmke)
#### Post date: [October 16, 2024, 4:10pm UTC](https://discourse.dry-rb.org/t/dry-validation-validate-keys-for-nested-array/1852/1 "2024-10-16T16:10:41Z")

</div>

I’m trying to catch unexpected keys in my (Rails-) API, using the following (simplified) code:

```ruby
require "dry-validation"

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

  params do
    required(:name).filled :string

    optional(:tel).maybe(:array).each do
      hash do
        required(:number).value :string, :filled?
        optional(:note).maybe :string
      end
    end
  end
end

```

> **(pp C.new)**
>
> ```auto
> #<C
> schema=#<Dry::Schema::Params
> keys=["name", {"tel"=>["number", "note"]}]
> rules={
> :name=>"key?(:name) AND key[name](filled? AND str?)",
> :tel=>"
> key?(:tel) THEN key[tel](
> not(nil?) THEN array? AND each(
> hash? AND set(
> key?(:number) AND key[number](str? AND filled?),
> key?(:note) THEN key[note](not(nil?) THEN str?)
> )
> )
> )
> "
> }
> >
> rules=[]
> >
> 
> ```

An unspecified (top-level) key returns an error, as expected:

```ruby
pp C.new.call(name: "Mario", random: 42, tel: [])
#=> #<Dry::Validation::Result{:name=>"Mario", :tel=>[]}
# errors={:random=>["is not allowed"]}>

```

However, filling the `:tel` array returns an unexpected error:

```ruby
pp C.new.call(name: "Luigi", tel: [{ number: "+1555123456" }])
#=> #<Dry::Validation::Result{:name=>"Luigi", :tel=>[{:number=>"+1555123456"}]}
# errors={:tel=>{0=>{:number=>["is not allowed"]}}}>

```

I’m not entirely sure what’s happening here. Am I doing something wrong?

---

<div class="post-metadata">

### Author: ![dmke](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/dmke/32/951_2.png) [@dmke](https://discourse.dry-rb.org/u/dmke)
#### Post date: [October 17, 2024, 1:17pm UTC](https://discourse.dry-rb.org/t/dry-validation-validate-keys-for-nested-array/1852/2 "2024-10-17T13:17:19Z")

</div>

Through trial and error, I’ve landed on

```ruby
require "dry-validation"

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

  params do
    required(:name).filled :string

    optional(:tel).array(:hash) do
      required(:number).filled(:string)
      optional(:note).maybe(:string)
    end
  end
end

```

This passes a few tests:

```ruby
def validate(**params)
  pp C.new.call(params).errors.to_h
end

test(name: "Mario") #=> {}
test(name: "Luigi", tel: [{ number: "+1555123456" }]) #=> {}
test(name: "Wario", tel: []) #=> {}

```

However, this requires the `tel` to be an array:

```ruby
test(name: "Peach", tel: nil) #=> {:tel=>["must be an array"]}

```

Is there a way to allow `nil` values? Semantically, this be equal to the Mario test case (i.e. as if `tel` wasn’t given at all).
