{"record":{"id":"7b0486c850fdabfa","repo":"crewAIInc/crewAI","slug":"filter-by-must-be-a-non-empty-column-name","errorCode":null,"errorMessage":"filter_by must be a non-empty column name.","messagePattern":"filter_by must be a non-empty column name\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/db2_search_tool/db2_search_tool.py","lineNumber":56,"sourceCode":"    filter_by: str | None = Field(\n        default=None,\n        description=(\n            \"Column name used for metadata filtering. \"\n            \"Must be used together with filter_value.\"\n        ),\n    )\n\n    filter_value: Any | None = Field(\n        default=None,\n        description=(\n            \"Value used for metadata filtering. Must be used together with filter_by.\"\n        ),\n    )\n\n    @model_validator(mode=\"after\")\n    def _validate_filter_pair(self) -> DB2ToolSchema:\n        if self.filter_by is not None and not self.filter_by.strip():\n            raise ValueError(\"filter_by must be a non-empty column name.\")\n        if (self.filter_by is None) ^ (self.filter_value is None):\n            raise ValueError(\"filter_by and filter_value must be provided together.\")\n        return self\n\n\nclass DB2VectorSearchTool(BaseTool):\n    \"\"\"\n    Fortified IBM DB2 Vector Search Tool.\n    Includes SQL injection protection, dynamic relational support, and type-safe serialization.\n    \"\"\"\n\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n\n    name: str = \"DB2VectorSearchTool\"\n    description: str = \"Search IBM DB2 vector database for relevant documents. Uses a custom embedding function if supplied, otherwise OpenAI embeddings.\"\n    args_schema: type[BaseModel] = DB2ToolSchema\n\n    # Internal Whitelist for distance metrics to prevent SQL injection","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/db2_search_tool/db2_search_tool.py#L38-L74","documentation":"DB2ToolSchema is a Pydantic model whose model_validator (_validate_filter_pair, mode='after') rejects a filter_by that is present but blank — an empty or whitespace-only string fails self.filter_by.strip(). The value names the metadata column used in the WHERE clause, so a blank identifier would build invalid SQL. The error surfaces at schema validation time, before any DB2 connection is attempted.","triggerScenarios":"Calling DB2VectorSearchTool._run with filter_by='' or filter_by='   ' (with or without filter_value); an LLM emitting an empty filter field in the tool JSON; code passing a variable that defaults to '' instead of None.","commonSituations":"Agent tool calls built from templates where optional fields become empty strings rather than being omitted; form inputs trimmed to nothing; config dicts using '' as the 'not set' sentinel.","solutions":["Omit filter_by entirely when no metadata filter is needed, or pass a real column name: filter_by='department', filter_value='sales'.","Normalize inputs before the call: convert blank strings to None so the pair check treats them as absent.","If building calls programmatically, only include filter keys when both have values."],"exampleFix":"# before\ntool._run(query='revenue report', filter_by='', filter_value='sales')\n\n# after\ntool._run(query='revenue report', filter_by='department', filter_value='sales')","handlingStrategy":"validation","validationCode":"def normalize_filter(filter_by: str | None, filter_value) -> tuple[str | None, object]:\n    if filter_by is not None and not filter_by.strip():\n        filter_by = None\n    if filter_by is None:\n        return None, None  # drop the pair entirely\n    return filter_by, filter_value","typeGuard":"def is_valid_filter_by(value: object) -> bool:\n    return value is None or (isinstance(value, str) and bool(value.strip()))","tryCatchPattern":"try:\n    tool._run(query=q, filter_by=fb, filter_value=fv)\nexcept ValidationError as e:\n    if 'filter_by' in str(e):\n        tool._run(query=q)  # retry without the metadata filter\n    else:\n        raise","preventionTips":["Treat blank strings as absent (convert to None) before building tool inputs.","Only include filter keys in the kwargs dict when both have real values.","Validate agent-emitted JSON with the same pydantic schema the tool uses."],"tags":["db2","pydantic","validation","vector-search","filter"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}