{"record":{"id":"8721e3a62719ccae","repo":"crewAIInc/crewAI","slug":"invalid-headers-e","errorCode":null,"errorMessage":"Invalid headers: {e}","messagePattern":"Invalid headers: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/tools/brave_search_tool/base.py","lineNumber":161,"sourceCode":"\r\n    @property\r\n    def headers(self) -> dict[str, Any]:\r\n        return self._headers\r\n\r\n    def set_headers(self, headers: dict[str, Any]) -> BraveSearchToolBase:\r\n        merged = {**self._headers, **{k.lower(): v for k, v in headers.items()}}\r\n        self._headers = self._build_and_validate_headers(merged)\r\n        return self\r\n\r\n    def _build_and_validate_headers(self, headers: dict[str, Any]) -> dict[str, Any]:\r\n        normalized = {k.lower(): v for k, v in headers.items()}\r\n        normalized.setdefault(\"x-subscription-token\", self._api_key)\r\n        normalized.setdefault(\"accept\", \"application/json\")\r\n\r\n        try:\r\n            self.header_schema(**normalized)\r\n        except Exception as e:\r\n            raise ValueError(f\"Invalid headers: {e}\") from e\r\n\r\n        return normalized\r\n\r\n    def _rate_limit(self) -> None:\r\n        \"\"\"Enforce minimum interval between requests for this instance. Thread-safe.\"\"\"\r\n        if self._requests_per_second <= 0:\r\n            return\r\n\r\n        min_interval = 1.0 / self._requests_per_second\r\n        with self._rate_limit_lock:\r\n            now = time.time()\r\n            next_allowed = self._last_request_time + min_interval\r\n            if now < next_allowed:\r\n                time.sleep(next_allowed - now)\r\n                now = time.time()\r\n            self._last_request_time = now\r\n\r\n    def _make_request(\r","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/tools/brave_search_tool/base.py#L143-L179","documentation":"BraveSearchTool normalizes custom headers (lowercased, with x-subscription-token and accept injected) and validates the merged dict against a Pydantic header_schema. Any schema violation — wrong value types, unexpected header names the schema rejects, or malformed values — is re-raised as ValueError('Invalid headers: ...') with the underlying validation error attached. This happens in the constructor and in update_headers().","triggerScenarios":"Passing headers={'X-Subscription-Token': 12345} (int instead of str); custom headers whose names or types the header_schema does not accept; header values containing newlines or non-ASCII that fail validation; calling update_headers() with similarly invalid entries.","commonSituations":"Reading header values from config/env without casting to str; passing an Authorization header the schema forbids; dict-of-dicts or None values from JSON config.","solutions":["Read the chained validation error text after 'Invalid headers:' — it names the exact failing field and reason.","Ensure all header keys and values are plain strings (cast: {str(k): str(v) for k, v in headers.items()}).","Only override headers the schema supports; for auth, rely on the api_key/BRAVE_API_KEY mechanism rather than hand-building the token header.","If you need x-subscription-token specifically, pass the key via api_key and let the tool inject it."],"exampleFix":"# before\ntool = BraveSearchTool(api_key=key, headers={\"X-Subscription-Token-Priority\": \"user\"})\n\n# after\ntool = BraveSearchTool(api_key=key, headers={\"x-subscription-token-priority\": \"user\"})  # valid schema field, lowercase str values","handlingStrategy":"validation","validationCode":"def sane_headers(headers: dict) -> dict:\n    return {str(k).lower(): str(v) for k, v in headers.items() if k and v is not None}","typeGuard":"def is_str_str_dict(d: object) -> bool:\n    return isinstance(d, dict) and all(\n        isinstance(k, str) and isinstance(v, str) and k and v for k, v in d.items()\n    )","tryCatchPattern":"try:\n    tool = BraveSearchTool(api_key=key, headers=custom)\nexcept ValueError as e:\n    if \"Invalid headers\" in str(e):\n        tool = BraveSearchTool(api_key=key)  # retry with defaults; add headers back one at a time\n    else:\n        raise","preventionTips":["Coerce all header keys/values to non-empty strings before passing them in.","Let the tool inject x-subscription-token from api_key instead of hand-building auth headers.","Add headers incrementally so a schema rejection identifies the offending one immediately."],"tags":["validation","headers","configuration","brave-search"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}