try-catch + ascii_downcase fails in "catch" condition
gursewak1997 opened this issue · comments
I see an error when we run a jq
statement using try-catch
and ascii_downcase
. If it has a match, it doesn't error out but when it needs to take the catch path, it errors out.
This issue was seen after upgrading the jq
from jq 1.6-17.fc39
-> jq-1.7.1-1.fc40
OS I am runnning on: Fedora CoreOS-Rawhide.
Steps to Reproduce:
- Run
jq -r 'map(select(try .baz catch "" | ascii_downcase == ""))' <<< '[{"foo":"bar"}]'
Actual results:
jq: error (at <stdin>:1): explode input must be a string
Expected results:
[
{
"foo": "bar"
}
]
@gursewak1997
I cannot reproduce that command not failing in jq 1.6
.
The exception is triggered by {"foo":"bar"} | .baz
returning null
succesfully (since there is not a "baz"
key in the object), and then null | ascii_downcase
being called, and ascii_downcase
is not in a try
block.
ascii_downcase
errors for non-string inputs in both jq 1.6
, jq 1.7
, and jq 1.7.1
.
{"foo":"bar"} | .baz
retruns null
in both jq 1.6
, jq 1.7
, and jq 1.7.1
. .baz
would only error if the input is neither null
nor an object. If the specified key is missing from the input object, or if the input is null
, it just returns null
in all versions of jq
, it does not error.
I don't get what is the point of using ascii_downcase == ""
either.
Nevermind, I can reproduce it now, I was using the wrong binary; sorry! ^^
Anyway, I think this was only not erroring because try
was bugged in many ways in jq 1.6
. Especially when used in combination with foreach
which was very annoying. :-(
If you try null | ascii_downcase
even in jq 1.6
it will error. And in that command, it is supposed to error.
I am not sure I understand what the intent of that jq
command is supposed to be.
If you want to only keep the objects that either don't contain .baz
or that have a .baz
equal to null
or ""
, I suggest using this instead:
jq 'del(.[] | select(.baz | IN(null, "") | not))'
# alternatively
jq 'del(.[] | select((.baz // "") != ""))'
jq 'map(select(.baz | IN(null, "")))'
jq 'map(select((.baz // "") == ""))'
If you want to only remove objects that contain a "baz"
in general, you can use:
jq 'del(.[] | select(has("baz")))'
# or, if you want to also keep objects with {"baz":null}
jq 'del(.[] | select(.baz != null))'
@emanuele6 For posterity, note the example here is just a minimal reproducer. The real world use case it was boiled down from can be seen in coreos/fedora-coreos-config#2797 (where we worked around it).