crewAIInc/crewAI · error · ValueError
filter_by must be a non-empty column name.
Error message
filter_by must be a non-empty column name.
What it means
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.
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/db2_search_tool/db2_search_tool.py:56
filter_by: str | None = Field(
default=None,
description=(
"Column name used for metadata filtering. "
"Must be used together with filter_value."
),
)
filter_value: Any | None = Field(
default=None,
description=(
"Value used for metadata filtering. Must be used together with filter_by."
),
)
@model_validator(mode="after")
def _validate_filter_pair(self) -> DB2ToolSchema:
if self.filter_by is not None and not self.filter_by.strip():
raise ValueError("filter_by must be a non-empty column name.")
if (self.filter_by is None) ^ (self.filter_value is None):
raise ValueError("filter_by and filter_value must be provided together.")
return self
class DB2VectorSearchTool(BaseTool):
"""
Fortified IBM DB2 Vector Search Tool.
Includes SQL injection protection, dynamic relational support, and type-safe serialization.
"""
model_config = ConfigDict(arbitrary_types_allowed=True)
name: str = "DB2VectorSearchTool"
description: str = "Search IBM DB2 vector database for relevant documents. Uses a custom embedding function if supplied, otherwise OpenAI embeddings."
args_schema: type[BaseModel] = DB2ToolSchema
# Internal Whitelist for distance metrics to prevent SQL injectionView on GitHub (pinned to 754d7323be)
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.
Example fix
# before tool._run(query='revenue report', filter_by='', filter_value='sales') # after tool._run(query='revenue report', filter_by='department', filter_value='sales')
Defensive patterns
Strategy: validation
Validate before calling
def normalize_filter(filter_by: str | None, filter_value) -> tuple[str | None, object]:
if filter_by is not None and not filter_by.strip():
filter_by = None
if filter_by is None:
return None, None # drop the pair entirely
return filter_by, filter_value Type guard
def is_valid_filter_by(value: object) -> bool:
return value is None or (isinstance(value, str) and bool(value.strip())) Try / catch
try:
tool._run(query=q, filter_by=fb, filter_value=fv)
except ValidationError as e:
if 'filter_by' in str(e):
tool._run(query=q) # retry without the metadata filter
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- filter_by and filter_value must be provided together.
- return_columns cannot be empty. At least one column must be
- Invalid distance metric: {metric}
- Missing required input '{name}'{suffix}
- Invalid input '{location}': {error.get('msg')}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/7b0486c850fdabfa.
Report an issue: GitHub.