crewAIInc/crewAI · error · ValueError

Client not initialized

Error message

Client not initialized

What it means

Defensive guard in ExaSearchTool._run: it refuses to execute a search when self.client is None. Under normal initialization __init__ always assigns self.client, so hitting this means the tool was constructed through an unusual path where the Exa client was never created (e.g. subclass bypassing __init__, or a failed/partial init left the attribute at its default).

Source

Thrown at lib/crewai-tools/src/crewai_tools/tools/exa_tools/exa_search_tool.py:132

            client_kwargs["api_key"] = self.api_key
        if self.base_url:
            client_kwargs["base_url"] = self.base_url
        self.client = Exa(**client_kwargs)
        self.client.headers["x-exa-integration"] = "crewai"
        self.content = content
        self.summary = summary
        self.highlights = highlights
        self.type = type

    def _run(
        self,
        search_query: str,
        start_published_date: str | None = None,
        end_published_date: str | None = None,
        include_domains: list[str] | None = None,
    ) -> Any:
        if self.client is None:
            raise ValueError("Client not initialized")

        search_params: SearchParams = {
            "type": self.type,
        }

        if start_published_date:
            search_params["start_published_date"] = start_published_date
        if end_published_date:
            search_params["end_published_date"] = end_published_date
        if include_domains:
            search_params["include_domains"] = include_domains

        contents_kwargs: dict[str, Any] = {}
        if self.content:
            contents_kwargs["text"] = self.content
        if self.highlights:
            contents_kwargs["highlights"] = self.highlights
        if self.summary:

View on GitHub (pinned to 754d7323be)

Solutions

  1. Construct the tool normally: ExaSearchTool(api_key=...) so __init__ builds self.client.
  2. If subclassing, call super().__init__(...) so the client is initialized.
  3. In tests, set tool.client to a mock Exa instance rather than leaving it None.

Example fix

# before
tool = ExaSearchTool.__new__(ExaSearchTool)
tool._run('query')  # ValueError

# after
tool = ExaSearchTool(api_key=EXA_API_KEY)
tool._run('query')
Defensive patterns

Strategy: type-guard

Validate before calling

if getattr(tool, 'client', None) is None:
    raise RuntimeError('ExaSearchTool built without a client; re-run its __init__')

Type guard

def has_exa_client(tool: 'ExaSearchTool') -> bool:
    return getattr(tool, 'client', None) is not None

Try / catch

try:
    results = tool._run('query')
except ValueError as e:
    if 'Client not initialized' in str(e):
        tool = ExaSearchTool(api_key=KEY)  # rebuild properly
        results = tool._run('query')
    else:
        raise

Prevention

When it happens

Trigger: Calling tool._run(...) on an ExaSearchTool instance whose __init__ did not complete the client assignment — e.g. object created via __new__ / model validation tricks, a subclass overriding __init__ without calling super, or monkeypatched/partially-mocked construction in tests.

Common situations: Unit tests constructing the tool with mocks that skip client setup; Pydantic model_copy/reconstruct paths that skip __init__; tampering with tool internals before running.

Related errors


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