Skip to content

Return false for contains(string, non-string) instead of raising TypeError#360

Open
gaoflow wants to merge 1 commit into
jmespath:developfrom
gaoflow:fix-contains-string-nonstring-typeerror
Open

Return false for contains(string, non-string) instead of raising TypeError#360
gaoflow wants to merge 1 commit into
jmespath:developfrom
gaoflow:fix-contains-string-nonstring-typeerror

Conversation

@gaoflow

@gaoflow gaoflow commented Jun 20, 2026

Copy link
Copy Markdown

Summary

contains() with a string subject and a non-string search raises an uncaught TypeError instead of returning false:

import jmespath
jmespath.search("contains(@, `123`)", "foobar")
# TypeError: 'in <string>' requires string as left operand, not int

This contradicts the JMESPath spec, which defines contains('foobar', 123) → false. It affects any non-string search against a string subject — number, boolean, null, array, or object.

The array case already returns false for a type-mismatched search of any type (contains([1,2,3], false) → false), because Python's in on a list accepts any right-hand type. Only the string path was inconsistent, since 123 in "foobar" raises.

Cause

Functions._func_contains was simply:

@signature({'types': ['array', 'string']}, {'types': []})
def _func_contains(self, subject, search):
    return search in subject

The signature permits a search of any type, but search in subject raises TypeError when subject is a string and search is not.

Fix

Guard the membership test: when the subject is a string and the search is not, return false (a non-string can never be a substring of a string). This brings the string path in line with the array path and the spec.

Verification

  • Added compliance cases for number, boolean and null searches against a string subject (tests/compliance/functions.json), each expecting false. They fail with TypeError before the fix and pass after (confirmed via git stash).
  • String-in-string and all array-membership behavior is unchanged.
  • Full suite: 994 passed, 1 skipped (was 991 + 1 skipped).

This pull request was prepared with the assistance of AI, under my direction and review.

contains() with a string subject and a non-string search raised an
uncaught TypeError ("'in <string>' requires string as left operand")
instead of returning false. The JMESPath spec defines
contains('foobar', `123`) as false, and the array case already returns
false for a type-mismatched search of any type, so the string and array
paths were inconsistent.

Guard the membership test: when the subject is a string and the search
is not, return false (a non-string can never be a substring). Adds
compliance cases for number, boolean and null searches.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant