{"record":{"id":"5cf529ec791a2dfe","repo":"datawhalechina/hello-agents","slug":"tavily-api-key-is-required-for-tavilysearchtool","errorCode":null,"errorMessage":"TAVILY_API_KEY is required for TavilySearchTool","messagePattern":"TAVILY_API_KEY is required for TavilySearchTool","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/afei-GuessWhoAmI/backend/tools/tavily_search_tool.py","lineNumber":24,"sourceCode":"\nfrom hello_agents.tools.base import Tool, ToolParameter\n\nlogger = logging.getLogger(\"game.tools\")\n\n\nclass TavilySearchTool(Tool):\n    \"\"\"Tavily web search tool - search-only, no AI answer generation\"\"\"\n\n    def __init__(self, api_key: str):\n        super().__init__(\n            name=\"tavily_search\",\n            description=(\n                \"Search the web for information about a historical figure. \"\n                \"Input the figure's name to retrieve relevant biographical information.\"\n            )\n        )\n        if not api_key:\n            raise ValueError(\"TAVILY_API_KEY is required for TavilySearchTool\")\n\n        from tavily import TavilyClient\n        self._client = TavilyClient(api_key=api_key)\n        logger.info(\"[TOOL] TavilySearchTool initialized\")\n\n    def run(self, parameters: Dict[str, Any]) -> str:\n        \"\"\"\n        Execute web search\n\n        Args:\n            parameters: dict with key 'query' - the search query string\n\n        Returns:\n            Concatenated search result snippets as a single string\n        \"\"\"\n        query = parameters.get(\"query\", \"\").strip()\n        if not query:\n            return \"Error: search query cannot be empty\"","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/afei-GuessWhoAmI/backend/tools/tavily_search_tool.py#L6-L42","documentation":"ValueError raised by TavilySearchTool.__init__ when the api_key argument is falsy (empty string or None). It is a constructor guard before TavilyClient is even imported, so the failure happens at agent/tool wiring time, not at search time — the game backend cannot start its search-capable agent without a key.","triggerScenarios":"Instantiating TavilySearchTool(os.environ.get('TAVILY_API_KEY')) when the env var is unset (get returns None); key set to '' in .env; .env not loaded because the process starts in the wrong cwd or python-dotenv was never invoked; key present in the shell but not passed to docker/systemd.","commonSituations":"Cloning the repo without creating .env from .env.example; docker compose service missing environment/env_file entries; systemd unit without EnvironmentFile; CI tests constructing the tool without injecting a dummy key.","solutions":["Obtain a Tavily API key (app.tavily.com free tier) and set TAVILY_API_KEY in backend/.env","Ensure .env loading happens before tool construction (load_dotenv() at entrypoint or pydantic-settings env_file)","For docker/systemd, pass the variable explicitly (env_file / EnvironmentFile=","In tests, inject a sentinel key or mock the tool so the constructor guard does not fire"],"exampleFix":"# before\ntool = TavilySearchTool(api_key=os.environ.get(\"TAVILY_API_KEY\"))\n# crashes at import/startup when unset\n\n# after\nfrom dotenv import load_dotenv\nload_dotenv()  # at process entry\n_api_key = os.environ.get(\"TAVILY_API_KEY\")\nif not _api_key:\n    raise RuntimeError(\n        \"缺少 TAVILY_API_KEY：请复制 .env.example 为 .env 并填入 key\"\n    )\ntool = TavilySearchTool(api_key=_api_key)","handlingStrategy":"validation","validationCode":"import os\n\ndef tavily_key_present() -> bool:\n    return bool(os.environ.get('TAVILY_API_KEY'))","typeGuard":"def has_api_key(key: str | None) -> bool:\n    return isinstance(key, str) and key.strip() != ''","tryCatchPattern":"try:\n    tool = TavilySearchTool(api_key=os.environ['TAVILY_API_KEY'])\nexcept (KeyError, ValueError) as e:\n    logger.warning('tavily unavailable (%s); building agent without web search', e)\n    tools = [t for t in tools if t is not tavily_tool]  # degrade gracefully","preventionTips":["Load .env at process entry (load_dotenv) before constructing tools","Fail fast at startup with a clear message listing missing keys instead of per-tool ValueErrors","In tests, inject a dummy key or patch TavilyClient so the guard does not fire"],"tags":["tavily","api-key","configuration","constructor","python"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}