mem0ai/mem0 · error · ValueError

All header keys and values must be strings

Error message

All header keys and values must be strings

What it means

Raised by the Elasticsearch config's header validator when headers is a dict but at least one key or value is not a str. HTTP headers are string-to-string mappings; ints, bools, or None values pass the isinstance(headers, dict) check and then fail this per-item string check.

Source

Thrown at mem0/configs/vector_stores/elasticsearch.py:51

        if not any([values.get("api_key"), (values.get("user") and values.get("password"))]):
            raise ValueError("Either api_key or user/password must be provided")

        return values

    @model_validator(mode="before")
    @classmethod
    def validate_headers(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        """Validate headers format and content"""
        headers = values.get("headers")
        if headers is not None:
            # Check if headers is a dictionary
            if not isinstance(headers, dict):
                raise ValueError("headers must be a dictionary")
            
            # Check if all keys and values are strings
            for key, value in headers.items():
                if not isinstance(key, str) or not isinstance(value, str):
                    raise ValueError("All header keys and values must be strings")
        
        return values

    @model_validator(mode="before")
    @classmethod
    def validate_extra_fields(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        allowed_fields = set(cls.model_fields.keys())
        input_fields = set(values.keys())
        extra_fields = input_fields - allowed_fields
        if extra_fields:
            raise ValueError(
                f"Extra fields not allowed: {', '.join(extra_fields)}. "
                f"Please input only the following fields: {', '.join(allowed_fields)}"
            )
        return values

    model_config = ConfigDict(arbitrary_types_allowed=True)

View on GitHub (pinned to 001c235229)

Solutions

  1. Convert all header values to strings: headers={k: str(v) for k, v in headers.items()}
  2. Drop None values before passing headers: {k: v for k, v in headers.items() if v is not None}
  3. Quote scalar header values in YAML/JSON so loaders keep them strings
  4. Add a quick assert that all(k, v are str) in config-loading code

Example fix

# before
ElasticsearchConfig(host="h", api_key="k", headers={"X-Opaque-Id": 42})

# after
ElasticsearchConfig(host="h", api_key="k", headers={"X-Opaque-Id": "42"})
Defensive patterns

Strategy: type-guard

Validate before calling

def validate_es_header_types(cfg: dict) -> None:
    h = cfg.get("headers")
    if isinstance(h, dict):
        bad = [k for k, v in h.items() if not isinstance(k, str) or not isinstance(v, str)]
        if bad:
            raise RuntimeError(f"Header keys/values must be str, bad entries: {bad}")

Type guard

def headers_all_str(cfg: dict) -> bool:
    h = cfg.get("headers")
    return h is None or (isinstance(h, dict) and all(isinstance(k, str) and isinstance(v, str) for k, v in h.items()))

Try / catch

from pydantic import ValidationError
try:
    ElasticsearchConfig(**cfg)
except ValidationError as e:
    if "keys and values must be strings" in str(e):
        # str() the values and drop Nones, then retry
        ...

Prevention

When it happens

Trigger: headers={"X-Retry": 3} (int value), headers={None: "v"} (non-str key), or headers={"flag": True}. Typically values injected from typed config sources (env ints, YAML booleans).

Common situations: YAML parsing 'on'/'off' into booleans used as header values; numeric settings passed through without str() conversion; None values from optional config fields not filtered out.

Related errors


AI-assisted analysis of mem0ai/mem0@001c235229 (2026-08-15). Data as JSON: /api/errors/d2117cb909842cd6. Report an issue: GitHub.