crewAIInc/crewAI · error · ValueError
Invalid headers: {e}
Error message
Invalid headers: {e} What it means
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().
Source
Thrown at lib/crewai-tools/src/crewai_tools/tools/brave_search_tool/base.py:161
@property
def headers(self) -> dict[str, Any]:
return self._headers
def set_headers(self, headers: dict[str, Any]) -> BraveSearchToolBase:
merged = {**self._headers, **{k.lower(): v for k, v in headers.items()}}
self._headers = self._build_and_validate_headers(merged)
return self
def _build_and_validate_headers(self, headers: dict[str, Any]) -> dict[str, Any]:
normalized = {k.lower(): v for k, v in headers.items()}
normalized.setdefault("x-subscription-token", self._api_key)
normalized.setdefault("accept", "application/json")
try:
self.header_schema(**normalized)
except Exception as e:
raise ValueError(f"Invalid headers: {e}") from e
return normalized
def _rate_limit(self) -> None:
"""Enforce minimum interval between requests for this instance. Thread-safe."""
if self._requests_per_second <= 0:
return
min_interval = 1.0 / self._requests_per_second
with self._rate_limit_lock:
now = time.time()
next_allowed = self._last_request_time + min_interval
if now < next_allowed:
time.sleep(next_allowed - now)
now = time.time()
self._last_request_time = now
def _make_request(
View on GitHub (pinned to 754d7323be)
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.
Example fix
# before
tool = BraveSearchTool(api_key=key, headers={"X-Subscription-Token-Priority": "user"})
# after
tool = BraveSearchTool(api_key=key, headers={"x-subscription-token-priority": "user"}) # valid schema field, lowercase str values Defensive patterns
Strategy: validation
Validate before calling
def sane_headers(headers: dict) -> dict:
return {str(k).lower(): str(v) for k, v in headers.items() if k and v is not None} Type guard
def is_str_str_dict(d: object) -> bool:
return isinstance(d, dict) and all(
isinstance(k, str) and isinstance(v, str) and k and v for k, v in d.items()
) Try / catch
try:
tool = BraveSearchTool(api_key=key, headers=custom)
except ValueError as e:
if "Invalid headers" in str(e):
tool = BraveSearchTool(api_key=key) # retry with defaults; add headers back one at a time
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Project name cannot be empty
- Project name '{name}' produces invalid folder name '{folder_
- No deployable project files were found.
- Missing required fields in OAuth2 configuration: [{', '.join
- Error: Unknown or readonly configuration key '{key}'
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/8721e3a62719ccae.
Report an issue: GitHub.