langflow-ai/langflow · warning · HTTPException

Metadata array '{key}' must contain only strings.

Error message

Metadata array '{key}' must contain only strings.

What it means

Array-valued metadata must be homogeneous lists of strings. If any element of the list is not a str (e.g. an int, dict, or nested list), _validate_value rejects the whole field with 422. This keeps metadata flat and predictable for the vector-store filters and the chunks browser that consume it.

Source

Thrown at src/backend/base/langflow/api/utils/kb_metadata.py:57

    return all(c in _KEY_ALLOWED_CHARS for c in key)


def _validate_value(key: str, value: Any) -> None:
    if isinstance(value, (bool, int, float)):
        return
    if isinstance(value, str):
        if len(value) > KB_METADATA_MAX_VALUE_LENGTH:
            msg = f"Metadata value for '{key}' exceeds {KB_METADATA_MAX_VALUE_LENGTH} characters."
            raise HTTPException(status_code=422, detail=msg)
        return
    if isinstance(value, list):
        if len(value) > KB_METADATA_MAX_ARRAY_LENGTH:
            msg = f"Metadata array '{key}' exceeds {KB_METADATA_MAX_ARRAY_LENGTH} items."
            raise HTTPException(status_code=422, detail=msg)
        for entry in value:
            if not isinstance(entry, str):
                msg = f"Metadata array '{key}' must contain only strings."
                raise HTTPException(status_code=422, detail=msg)
            if len(entry) > KB_METADATA_MAX_VALUE_LENGTH:
                msg = f"Metadata array entry under '{key}' exceeds {KB_METADATA_MAX_VALUE_LENGTH} characters."
                raise HTTPException(status_code=422, detail=msg)
        return
    msg = f"Metadata value for '{key}' must be a string, number, bool, or string array; got {type(value).__name__}."
    raise HTTPException(status_code=422, detail=msg)


def validate_user_metadata(metadata: dict[str, Any]) -> dict[str, Any]:
    """Enforce the user-metadata contract on a decoded dict.

    Returns the same dict (a shallow copy is *not* made — callers may mutate
    safely once validation passes). Raises :class:`HTTPException` with a 422
    status on any violation so FastAPI surfaces an inline error.
    """
    if not isinstance(metadata, dict):
        msg = "Metadata must be a JSON object."
        raise HTTPException(status_code=422, detail=msg)

View on GitHub (pinned to 976ec789d2)

Solutions

  1. Coerce every array element to str before submitting: [str(x) for x in items].
  2. Model numbers as separate scalar keys ({"priority": 3}) rather than inside arrays.
  3. Validate the shape client-side with a JSON-schema or a small guard before the multipart POST (see defense section).
  4. For dicts inside arrays, flatten to 'key:value' strings or store externally.

Example fix

# before
metadata = {"tags": ["nlp", 42, None]}  # 422

# after
metadata = {"tags": [str(t) for t in ("nlp", 42) if t is not None], "rank": 42}
Defensive patterns

Strategy: type-guard

Validate before calling

def coerce_arrays(meta: dict) -> dict:
    return {k: ([str(x) for x in v] if isinstance(v, list) else v) for k, v in meta.items()}

Type guard

def is_homogeneous_string_array(v) -> bool:
    return not isinstance(v, list) or (len(v) <= 16 and all(isinstance(x, str) for x in v))

Try / catch

try:
    validate_user_metadata(meta)
except HTTPException as e:
    if e.status_code == 422 and 'must contain only strings' in e.detail:
        meta = {k: ([str(x) for x in v] if isinstance(v, list) else v) for k, v in meta.items()}
        validate_user_metadata(meta)
    else:
        raise

Prevention

When it happens

Trigger: A metadata JSON like {"tags": ["ml", 42]} or {"refs": [{"id": 1}]} in the metadata or per_file_metadata form field of a KB ingest request. Note bool is NOT an accepted array element (bool is a valid scalar type but arrays must be all-strings), and the type check runs before the per-entry length check.

Common situations: JSON produced by json.dumps of mixed Python lists; tagging systems that emit [id, label] pairs; LLM-generated metadata where the model mixes types; per-file metadata maps built generically from ORM objects.

Related errors


AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14). Data as JSON: /api/errors/6df533a5b936d6f5. Report an issue: GitHub.