From 1aa6be3097d5c132ce57119a0e381c74d2d617ff Mon Sep 17 00:00:00 2001 From: chrikrah <48338417+chrikrah@users.noreply.github.com> Date: Sat, 26 Sep 2026 14:12:28 +0000 Subject: [PATCH] fix(query): accept a bare string for include_vector INCLUDE_VECTOR is Union[bool, str, List[str]], and the validator accepts bool, str and Sequence, so passing one named vector as a string is a valid call. _MetadataQuery.from_public handled only bool and list, so a str matched neither branch: MetadataRequest asked for no vector at all and the caller got none back, with no error. _QueryOptions meanwhile recorded include_vector=True, so the response parser was told to expect one. Normalises str to [str] at the top of from_public. --- test/collection/test_include_vector_str.py | 32 ++++++++++++++++++++++ weaviate/collections/classes/grpc.py | 5 ++++ 2 files changed, 37 insertions(+) create mode 100644 test/collection/test_include_vector_str.py diff --git a/test/collection/test_include_vector_str.py b/test/collection/test_include_vector_str.py new file mode 100644 index 000000000..bfb3eae59 --- /dev/null +++ b/test/collection/test_include_vector_str.py @@ -0,0 +1,32 @@ +"""`include_vector` accepts a bare ``str`` but then requests no vector at all. + +``INCLUDE_VECTOR = Union[bool, str, List[str]]`` and ``_parse_return_metadata`` +validates ``[bool, str, Sequence]``, so a single named vector may be passed as a +string. ``_MetadataQuery.from_public`` only handles ``bool`` and ``list``, so a +string falls through both branches and the gRPC ``MetadataRequest`` asks for +nothing, while ``_QueryOptions`` still reports ``include_vector=True``. +""" + +from weaviate.collections.classes.grpc import _MetadataQuery +from weaviate.collections.classes.internal import _QueryOptions + + +def test_metadata_query_from_public_with_a_list() -> None: + """Baseline: the list form requests the named vector.""" + md = _MetadataQuery.from_public(None, ["named_vec"]) + assert md.vectors == ["named_vec"] + + +def test_metadata_query_from_public_with_a_bare_string() -> None: + md = _MetadataQuery.from_public(None, "named_vec") + assert md.vectors == ["named_vec"], ( + f"a bare str requested nothing: vector={md.vector!r} vectors={md.vectors!r}" + ) + + +def test_query_options_and_metadata_query_agree_for_a_bare_string() -> None: + """The parser is told a vector is coming; the request never asked for one.""" + opts = _QueryOptions.from_input(None, None, "named_vec", None, None) + md = _MetadataQuery.from_public(None, "named_vec") + assert opts.include_vector is True + assert bool(md.vector) or md.vectors, "include_vector=True but nothing was requested" diff --git a/weaviate/collections/classes/grpc.py b/weaviate/collections/classes/grpc.py index 5cba315f7..a340f8bfc 100644 --- a/weaviate/collections/classes/grpc.py +++ b/weaviate/collections/classes/grpc.py @@ -148,6 +148,11 @@ class _MetadataQuery: def from_public( cls, public: Optional[MetadataQuery], include_vector: INCLUDE_VECTOR ) -> "_MetadataQuery": + # INCLUDE_VECTOR permits a bare `str` for a single named vector, and the branches below + # test only for `bool` and `list`. Without this a `str` matched neither, so the request + # asked for no vector at all and the caller got none back, with no error. + if isinstance(include_vector, str): + include_vector = [include_vector] return ( cls( vector=include_vector if isinstance(include_vector, bool) else False,