Repository: jekyll/jekyll (Ruby)

Issue:
[Bug]: Unexpected crash: filters.rb:442:in `read_liquid_attribute': no implicit conversion of String into Integer
### Operating System

OSX

### Ruby Version

ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21]

### Jekyll Version

jekyll 4.2.1

### GitHub Pages Version

_No response_

### Expected Behavior

Should build without error

### Current Behavior

Crashes with a weird error:  filters.rb:442:in `read_liquid_attribute': no implicit conversion of String into Integer

### Relevant log output

```shell
/Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/filters.rb:442:in `read_liquid_attribute': no implicit conversion of String into Integer (TypeError)
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/filters.rb:430:in `item_property'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/filters.rb:199:in `block in where'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/filters.rb:198:in `select'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/filters.rb:198:in `where'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/strainer.rb:56:in `invoke'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/context.rb:86:in `invoke'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/variable.rb:84:in `block in render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/variable.rb:82:in `each'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/variable.rb:82:in `inject'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/variable.rb:82:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/tags/assign.rb:26:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:103:in `render_node_to_output'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:91:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/tags/if.rb:46:in `block (2 levels) in render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/tags/if.rb:44:in `each'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/tags/if.rb:44:in `block in render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/context.rb:123:in `stack'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/tags/if.rb:43:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:103:in `render_node_to_output'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:82:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:208:in `block in render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:242:in `with_profiling'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:207:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:220:in `render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:39:in `block (3 levels) in render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:59:in `measure_counts'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:38:in `block (2 levels) in render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:63:in `measure_bytes'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:37:in `block in render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:70:in `measure_time'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:36:in `render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/inclusion.rb:16:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/tags/include.rb:208:in `block in render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/context.rb:123:in `stack'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/tags/include.rb:206:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:103:in `render_node_to_output'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/block_body.rb:91:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:208:in `block in render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:242:in `with_profiling'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:207:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/liquid-4.0.3/lib/liquid/template.rb:220:in `render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:39:in `block (3 levels) in render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:59:in `measure_counts'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:38:in `block (2 levels) in render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:63:in `measure_bytes'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:37:in `block in render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:70:in `measure_time'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/liquid_renderer/file.rb:36:in `render!'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/renderer.rb:131:in `render_liquid'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/renderer.rb:80:in `render_document'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/renderer.rb:63:in `run'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/site.rb:547:in `render_regenerated'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/site.rb:539:in `block in render_pages'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/site.rb:538:in `each'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/site.rb:538:in `render_pages'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/site.rb:211:in `render'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/site.rb:80:in `process'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/command.rb:28:in `process_site'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/commands/build.rb:65:in `build'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/commands/build.rb:36:in `process'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/command.rb:91:in `block in process_with_graceful_fail'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/command.rb:91:in `each'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/command.rb:91:in `process_with_graceful_fail'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/lib/jekyll/commands/build.rb:18:in `block (2 levels) in init_with_program'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `block in execute'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `each'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/mercenary-0.4.0/lib/mercenary/command.rb:221:in `execute'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/mercenary-0.4.0/lib/mercenary/program.rb:44:in `go'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/mercenary-0.4.0/lib/mercenary.rb:21:in `program'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/gems/jekyll-4.2.1/exe/jekyll:15:in `<top (required)>'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/bin/jekyll:25:in `load'
	from /Users/grahamegrieve/.gem/ruby/3.1.0/bin/jekyll:25:in `<main>'
```


### Code Sample

See attached zip file. The error may be removed by removing the last entry in the json file pages/data/structuredefinitions.json (the "extensionContextsPopulated" : [ "none" ]) bit), or just converting it to "extensionContextsPopulated" : "none" 

[pages.zip](https://github.com/jekyll/jekyll/files/10576589/pages.zip)



Discussion: This is technically a bug at your end.
You have total control over `site.data.structuredefinitions` and how you consume it.
All top-level values of `structuredefinitions.json` are Hashes or *objects* except for the last value which is an Array.
Jekyll's `where` filter traverses given object by calling `[]` on each top-level key. Your include file has `site.data.structuredefinitions | where: "path", ...`. While `hash["path"]` is valid, `array["path"]` is an invalid usage and hence the error.
My opinion is that Jekyll should continue to throw error on invalid usage instead of silently bypassing such usage.
I do not see any documentation anywhere stating such restrictions on json files. It's true that I have total control over the json file. but such restrictions are a very abnormal aspect of using json. However, it is a completely mystifying error message for the issue, one that proved extremely difficult to identify the cause for, and at the very least, users should get a coherent issue report, not "no implicit conversion of String into Integer"
I agree with all of your statements, @grahamegrieve. It took me some time to pinpoint the root cause even though I staight away knew the error had something to do with the `where` filter (evident from the backtrace).

I will consider surfacing a better *error message* to reduce the confusion at the user-level.

I also apologize for showing reluctance to own the oversight at the program level in my previous comment. There was no clear way for the user to tell if the bug was at their end.

Thank you for providing a comprehensive bug report along with the code sample. For future reference, it is always preferable if the code sample was a GitHub repository (with minimal content, especially since you were already able to come with a solution).
ok, thanks. 



Fix (patch):
diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb
index 5422d52a492..7a79eec9eb6 100644
--- a/lib/jekyll/filters.rb
+++ b/lib/jekyll/filters.rb
@@ -441,6 +441,14 @@ def read_liquid_attribute(liquid_data, property)
       property.split(".").reduce(liquid_data) do |data, key|
         data.respond_to?(:[]) && data[key]
       end
+    rescue TypeError => e
+      msg = if liquid_data.is_a?(Array)
+              "Error accessing object (#{liquid_data.to_s[0...20]}) with given key. Expected an " \
+                "integer but got #{property.inspect} instead."
+            else
+              e.message
+            end
+      raise e, msg
     end
 
     FLOAT_LIKE   = %r!\A\s*-?(?:\d+\.?\d*|\.\d+)\s*\Z!.freeze