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 injection

View on GitHub (pinned to 754d7323be)

Solutions

  1. Omit filter_by entirely when no metadata filter is needed, or pass a real column name: filter_by='department', filter_value='sales'.
  2. Normalize inputs before the call: convert blank strings to None so the pair check treats them as absent.
  3. 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

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


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/7b0486c850fdabfa. Report an issue: GitHub.