Repository navigation
fix(jmespath): stop sort() and reverse() from mutating the input array - #5823
Closed
unknownhackerworld wants to merge 1 commit into
Closed
unknownhackerworld wants to merge 1 commit into
unknownhackerworld wants to merge 1 commit into
Conversation
svozza
reviewed
Oct 20, 2026
| public funcReverse(arg: string | Array<unknown>): string | Array<unknown> { | ||
| return Array.isArray(arg) | ||
| ? arg.reverse() | ||
| ? [...arg].reverse() |
Contributor
There was a problem hiding this comment.
Can we use toReversed instead?
| }) | ||
| public funcSort(arg: Array<string> | Array<number>): Array<unknown> { | ||
| return arg.sort((a: string | number, b: string | number): number => { | ||
| return [...arg].sort((a: string | number, b: string | number): number => { |
Contributor
There was a problem hiding this comment.
Can we use toSorted in stead here?
Contributor
|
Hi @unknownhackerworld - are you still interested in completing this PR? If yes, please try to address the comments by the end of the week, if not and priorities have changed we’ll close it on Monday - that’s not an issue, and you’re welcome to contribute another PR in the future. |
Signed-off-by: Allen Joseph G <63872540+unknownhackerworld@users.noreply.github.com>
unknownhackerworld
force-pushed
the
fix/jmespath-sort-reverse-mutation
branch
from
October 25, 2026 11:28
63e797e to
1954631
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changes
sort()andreverse()sorted and reversed the caller's array in place, so evaluating an expression changed the data it read. Both functions now work on a copy and leave the input untouched.Root cause
In
packages/jmespath/src/Functions.ts,funcSortreturnedarg.sort(...)andfuncReversereturnedarg.reverse()for arrays.Array.prototype.sortandArray.prototype.reverseboth mutate the array they are called on, andargis the array from the caller's object, not a copy (the tree interpreter passes field values by reference). Sosearch('sort(numbers)', data)returned the sorted array and also leftdata.numberssorted.This reaches the utilities that call
search()on the Lambda event:eventKeyJmesPathon the event before it runs the handler (IdempotencyHandlerandBasePersistenceLayer.getHashedIdempotencyKey).makeIdempotentpasses the handler's own argument (makeIdempotent.ts,functionPayloadToBeHashed = args[0]), so witheventKeyJmesPath: 'sort(items)'the handler receivedevent.itemsalready reordered. I reproduced this withmakeIdempotentand thePersistenceLayerTestClasshelper: the handler saw['a', 'b', 'c']for an event sent with['b', 'c', 'a']. With this change it sees['b', 'c', 'a'].validationKeyJmesPath, to Validation envelopes (validate.ts) and to any directsearch()call.The Python reference implementation (
jmespath.py, used by Powertools for AWS Lambda (Python)) returns new lists from both functions (sorted(arg)andlist(reversed(arg))), so this was a TypeScript-only divergence.Fix
Copy the array before the in-place call:
[...arg].sort(...)and[...arg].reverse(). The comparator, the string branch ofreverse()(which already builds a new string) and the return types are unchanged. I checked the other functions in the file:sort_by()already sorts a new array produced bymap(), andmax_by(),min_by(),map()andmerge()do not mutate their input.Tests
In
packages/jmespath/tests/unit/compliance/functions.test.ts, a newit.eachevaluatessort(numbers),sort(strings)andreverse(numbers)and checks both the result and that the input object is unchanged. All three cases fail onmainand pass with this change.npm run test:unit:coverage -w packages/jmespathpasses with 100% coverage (891 tests), andbiome ciandnpm run build:testsare clean.Tradeoffs and alternatives
sort()is already O(n log n), so I did not think it was worth avoiding.Array.prototype.toSorted()andtoReversed()would also work, since the project targets ES2024 and Node.js 22. I used the spread copy because it is the smallest change to the existing calls and keeps the comparator untouched. Happy to switch totoSorted()/toReversed()if you prefer them.search()in Idempotency and Validation would also hide the problem, but it costs more on every invocation and leaves directsearch()callers exposed. Fixing the two functions keeps evaluation side-effect free for every caller.Issue number: closes #5822
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
Disclaimer: We value your time and bandwidth. As such, any pull requests created on non-triaged issues might not be successful.