{"record":{"id":"c91f856173369fe0","repo":"jd-opensource/joyagent-jdgenie","slug":"type-val-key","errorCode":null,"errorMessage":"❌ 不支持的过滤值类型: {type(val)}，字段: {key}","messagePattern":"❌ 不支持的过滤值类型: (.+?)，字段: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"genie-tool/genie_tool/util/qdrant_utils.py","lineNumber":198,"sourceCode":"            for key, val in filters.items():\n                if isinstance(val, (str, bool, int, float)):\n                    must_conditions.append(\n                        FieldCondition(key=key, match=MatchValue(value=val))\n                    )\n                elif isinstance(val, list):\n                    must_conditions.append(\n                        FieldCondition(key=key, match=MatchAny(any=val))\n                    )\n                elif isinstance(val, dict):\n                    range_args = {}\n                    for op in [\"gte\", \"gt\", \"lte\", \"lt\"]:\n                        if op in val:\n                            range_args[op] = val[op]\n                    must_conditions.append(\n                        FieldCondition(key=key, range=Range(**range_args))\n                    )\n                else:\n                    raise ValueError(f\"❌ 不支持的过滤值类型: {type(val)}，字段: {key}\")\n            \n            query_filter = Filter(must=must_conditions) if must_conditions else None\n            \n            delete_request = self.client.delete(\n            collection_name=self.collection_name,\n            points_selector=query_filter  # 👈 旧版也支持\n        )\n        \n        return self.client.delete(collection_name=self.collection_name, points_selector=delete_request)\n    \n    def search(self, query_vector, filters):\n        must_conditions = []\n        \n        for key, val in filters.items():\n            if isinstance(val, (str, bool, int, float)):\n                must_conditions.append(\n                    FieldCondition(\n                        key=key,","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/jd-opensource/joyagent-jdgenie/blob/2417e0b8b636d941ad5fb14c59b20dddfef5375d/genie-tool/genie_tool/util/qdrant_utils.py#L180-L216","documentation":"QdrantUtils.delete builds a Filter from a filters dict and raises ValueError when a field's value is of an unsupported type for the condition builder. Supported shapes are match-style values and range dicts ({\"gte\":..,\"lte\":..}); anything else (nested dict without range ops, list, None value) is rejected.","triggerScenarios":"delete(filters={...}) where some field value is not a scalar (str/int/float/bool) and not a dict containing range operators like gte/lte/gt/lt — e.g. filters={\"tags\": [\"a\",\"b\"]} (list) or a nested dict of unsupported structure.","commonSituations":"Passing SQL/elastic-style query dicts into Qdrant filters; assuming list values mean 'match any'; a shared filter-building helper used by search() reused with wrong value shapes; schema drift where a field became an array in stored payloads.","solutions":["Convert list values to explicit must/should match conditions (one FieldCondition per element) before calling delete","Use only scalars for equality: filters={\"status\": \"old\"} instead of filters={\"status\": [\"a\",\"b\"]}","For numeric comparisons use the range dict form: filters={\"created_at\": {\"gte\": 1700000000, \"lte\": 1800000000}}","Extend the filter builder to handle the unsupported type instead of raising, if lists are a legitimate use case"],"exampleFix":"// before\nqdrant.delete(filters={\"category\": [\"a\", \"b\"]})  # ValueError: 不支持的过滤值类型: list\n// after\nfor cat in [\"a\", \"b\"]:\n    qdrant.delete(filters={\"category\": cat})","handlingStrategy":"type-guard","validationCode":"RANGE_OPS = {'gte','lte','gt','lt'}\ndef delete_filters_supported(filters):\n    for key, val in (filters or {}).items():\n        if isinstance(val, dict):\n            if not (set(val) & RANGE_OPS):\n                return False, f'{key}: dict without range ops'\n        elif not isinstance(val, (str, int, float, bool)):\n            return False, f'{key}: {type(val).__name__} unsupported'\n    return True, None","typeGuard":"def is_scalar_or_range(v):\n    return isinstance(v, (str, int, float, bool)) or (isinstance(v, dict) and any(k in v for k in ('gte','lte','gt','lt')))","tryCatchPattern":"try:\n    qdrant.delete(filters=filters)\nexcept ValueError as e:\n    logger.error('unsupported filter shape: %s', e)\n    # fall back to per-scalar deletes or fix the filter","preventionTips":["Keep filter values scalar or range-op dicts","Translate cross-store filter syntax before calling Qdrant","Test filter dicts against search() (same builder) before delete","Document supported filter shapes in shared utils"],"tags":["qdrant","filter","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"2417e0b8b636d941ad5fb14c59b20dddfef5375d","analyzedAt":"2026-09-08T11:28:19.414Z","contentChangedAt":"2026-09-08T11:28:19.414Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}