yq
yq copied to clipboard
panic: runtime error: index out of range [1] with length 1
When trying to add a additionnal tag to a xml file, yq crash with the error panic: runtime error: index out of range [1] with length 1.
Version of yq: 4.27.5 Operating system: Ubuntu 22.04 Impish Indri Installed via: binary ( yq_linux_amd64.tar.gz )
Input document
File: /etc/iwatch/iwatch.xml
<config charset="utf-8">
<guard email="iwatch@localhost" name="iWatch"></guard>
<watchlist><title>Operating System</title></watchlist>
</config>
Command
sudo yq --inplace --input-format='xml' --output-format='xml' \
'eval' ".config.watchlist |= . + [ {
\"title\": \"Some title\"
} ]" \
"/etc/iwatch/iwatch.xml"
Actual behavior
panic: runtime error: index out of range [1] with length 1
goroutine 1 [running]:
github.com/mikefarah/yq/v4/pkg/yqlib.addMaps(0xc0002aab80, 0xc00033ac20?, 0x40d51f?)
/home/runner/work/yq/yq/pkg/yqlib/operator_add.go:189 +0x3c6
github.com/mikefarah/yq/v4/pkg/yqlib.add(0xc000282450?, {0xc00035cb40, 0xc00035cbd0, 0x1, {0x0, 0x0}}, 0xc0002aa800, 0xc0002aa880)
/home/runner/work/yq/yq/pkg/yqlib/operator_add.go:65 +0x510
github.com/mikefarah/yq/v4/pkg/yqlib.resultsForRHS(0x19?, {0xc00035cb40, 0xc00035cbd0, 0x1, {0x0, 0x0}}, 0x28?, {0x0, 0x0, 0x8bbdd0}, ...)
/home/runner/work/yq/yq/pkg/yqlib/operators.go:105 +0x62a
github.com/mikefarah/yq/v4/pkg/yqlib.doCrossFunc(0x1d?, {0xc00035cb40, 0xc00035cbd0, 0x1, {0x0, 0x0}}, 0xc000288468, {0x0, 0x0, 0x8bbdd0})
/home/runner/work/yq/yq/pkg/yqlib/operators.go:142 +0x413
github.com/mikefarah/yq/v4/pkg/yqlib.crossFunctionWithPrefs(0x1?, {0xc00035ca20, 0xc00035c870, 0x1, {0x0, 0x0}}, 0xc00035c8d0?, {0x0, 0x0, 0x8bbdd0})
/home/runner/work/yq/yq/pkg/yqlib/operators.go:175 +0x3db
github.com/mikefarah/yq/v4/pkg/yqlib.crossFunction(0xc000282450?, {0xc00035ca20, 0xc00035c870, 0x1, {0x0, 0x0}}, 0x0?, 0xc5a5a0?, 0x70?)
/home/runner/work/yq/yq/pkg/yqlib/operators.go:153 +0x9f
github.com/mikefarah/yq/v4/pkg/yqlib.addOperator(0xc000282450?, {0xc00035c7e0, 0xc00035c870, 0x0, {0x0, 0x0}}, 0x0?)
/home/runner/work/yq/yq/pkg/yqlib/operator_add.go:46 +0x1c5
github.com/mikefarah/yq/v4/pkg/yqlib.(*dataTreeNavigator).GetMatchingNodes(0xc000282450?, {0xc00035c7e0, 0xc00035c870, 0x0, {0x0, 0x0}}, 0xc000288468)
/home/runner/work/yq/yq/pkg/yqlib/data_tree_navigator.go:37 +0x25c
github.com/mikefarah/yq/v4/pkg/yqlib.assignUpdateOperator(0xc000282450?, {0xc00035c3f0, 0x0, 0x0, {0x0, 0x0}}, 0xc000288480)
/home/runner/work/yq/yq/pkg/yqlib/operator_assign.go:52 +0x56e
github.com/mikefarah/yq/v4/pkg/yqlib.(*dataTreeNavigator).GetMatchingNodes(0x0?, {0xc00035c3f0, 0x0, 0x0, {0x0, 0x0}}, 0xc000288480)
/home/runner/work/yq/yq/pkg/yqlib/data_tree_navigator.go:37 +0x25c
github.com/mikefarah/yq/v4/pkg/yqlib.(*streamEvaluator).Evaluate(0xc000229cf0, {0x7ffc9d60d7f9, 0x16}, {0x93cbe0?, 0xc000286600?}, 0x7f13e90a6cc8?, {0x93ee38, 0xc0002864e0}, {0x0, 0x0}, ...)
/home/runner/work/yq/yq/pkg/yqlib/stream_evaluator.go:124 +0x363
github.com/mikefarah/yq/v4/pkg/yqlib.(*streamEvaluator).EvaluateFiles(0xc00028a4d0?, {0x7ffc9d60d7bc, 0x3c}, {0xc0002c0010, 0x1, 0xc0002a0800?}, {0x93ee38, 0xc0002864e0}, 0xec?, {0x93e0a8, ...})
/home/runner/work/yq/yq/pkg/yqlib/stream_evaluator.go:73 +0x30e
github.com/mikefarah/yq/v4/cmd.evaluateSequence(0xc0002a4280?, {0xc0002c0000, 0x2, 0x5})
/home/runner/work/yq/yq/cmd/evalute_sequence_command.go:132 +0x8a5
github.com/spf13/cobra.(*Command).execute(0xc0002a4280, {0xc0002863c0, 0x5, 0x6})
/home/runner/go/pkg/mod/github.com/spf13/[email protected]/command.go:872 +0x694
github.com/spf13/cobra.(*Command).ExecuteC(0xc0002a4000)
/home/runner/go/pkg/mod/github.com/spf13/[email protected]/command.go:990 +0x3bd
github.com/spf13/cobra.(*Command).Execute(...)
/home/runner/go/pkg/mod/github.com/spf13/[email protected]/command.go:918
main.main()
/home/runner/work/yq/yq/yq.go:22 +0x1e5
Expected behavior
<config charset="utf-8">
<guard email="iwatch@localhost" name="iWatch"></guard>
<watchlist>
<title>Operating System</title>
</watchlist>
<watchlist>
<title>Some title</title>
</watchlist>
</config>
Additional context
When there is two watchlist tags in the input document, the command works without issue.
<config charset="utf-8">
<guard email="iwatch@localhost" name="iWatch"></guard>
<watchlist><title>Operating System</title></watchlist>
<watchlist><title>Some other title</title></watchlist>
</config>
Ah I see - there are two issues here.
- If there's a single item in the XML,
yqhas no way of knowing that it's an array of one. Sowatchlistin the first example is a map, but in the second example, it's an array. - I failed to add validation when adding to a map that the right hand side is a map (fix in next release).
To get what you want, you have to wrap watchlist into an array (if it's not one already) and then append to it:
yq -p=xml -o=xml '.config.watchlist |= (select(tag == "!!seq") // [.]) + [{"x": "y"}]' file.xml
The key bit is: (select(tag == "!!seq") // [.]) which will use watchlist as-is if it's a sequence, otherwise it will wrap it into an array.
Thank you for you help. The only drawback of your command is that when "watchlist" is not present, it add a <watchlist>null</watchlist> tag to the XML in addition to the new content.
I managed to fix this by using:
yq -p=xml -o=xml '.config.watchlist |= (select(tag == "!!seq") // [ select(length > 0) ]) + [{"x": "y"}]' file.xml
Thank you for your work on yq, it is a great tool to programmatically edit yaml, json and xml files :)
Pleasure :) That's an easy fix as well - I'm not at my pc with yq atm but it will be something like:
yq -p=xml -o=xml 'select(has(.config.watchlist)) | .config.watchlist |= (select(tag == "!!seq") // [.]) + [{"x": "y"}]' file.xml
Fixed in 4.28.2