langflow-ai/langflow · warning · HTTPException
Metadata key {key!r} is invalid: must be 1-{KB_METADATA_MAX_
Error message
Metadata key {key!r} is invalid: must be 1-{KB_METADATA_MAX_KEY_LENGTH} lowercase alphanumeric or underscore characters. What it means
Every metadata key must be 1-32 characters (KB_METADATA_MAX_KEY_LENGTH) and consist only of lowercase letters, digits, and underscores — the exact charset in _KEY_ALLOWED_CHARS. The key is also rejected if it is not a string at all. Uppercase letters, hyphens, spaces, dots, and unicode all fail with this 422 message, which interpolates the offending key via repr().
Source
Thrown at src/backend/base/langflow/api/utils/kb_metadata.py:85
"""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)
if len(metadata) > KB_METADATA_MAX_KEYS:
msg = f"Metadata exceeds the {KB_METADATA_MAX_KEYS} key limit."
raise HTTPException(status_code=422, detail=msg)
for key, value in metadata.items():
if not isinstance(key, str) or not _is_valid_key(key):
msg = (
f"Metadata key {key!r} is invalid: must be 1-{KB_METADATA_MAX_KEY_LENGTH} "
"lowercase alphanumeric or underscore characters."
)
raise HTTPException(status_code=422, detail=msg)
if key in KB_METADATA_RESERVED_KEYS:
msg = f"Metadata key '{key}' is reserved for ingestion-internal use."
raise HTTPException(status_code=422, detail=msg)
_validate_value(key, value)
return metadata
def parse_user_metadata(raw: str | None) -> dict[str, Any]:
"""Decode + validate the ``metadata`` form field. Empty/None → ``{}``."""
if not raw:
return {}
try:
decoded = json.loads(raw)
except json.JSONDecodeError as exc:
msg = f"Metadata is not valid JSON: {exc.msg}"
raise HTTPException(status_code=422, detail=msg) from exc
return validate_user_metadata(decoded)
View on GitHub (pinned to 976ec789d2)
Solutions
- Normalize keys before submission: lower(), replace non-alphanumerics with '_', trim to 32 chars, collapse repeats.
- Adopt a fixed snake_case vocabulary for metadata keys in your ingestion pipeline.
- Watch out for a normalization collision ('Doc-Type' and 'doc type' both -> 'doc_type') — dedupe after normalizing.
- Add a regex guard on the client: ^[a-z0-9_]{1,32}$ per key.
Example fix
# before
metadata = {"Doc-Type": "pdf", "file.name": "a.pdf"} # 422
# after
import re
def norm_key(k: str) -> str:
k2 = re.sub(r'[^a-z0-9_]', '_', k.lower())[:32]
return k2
metadata = {norm_key(k): v for k, v in raw.items()} Defensive patterns
Strategy: validation
Validate before calling
import re
from langflow.utils.kb_constants import KB_METADATA_MAX_KEY_LENGTH as MAXKL
def normalize_keys(meta: dict) -> dict:
out = {}
for k, v in meta.items():
nk = re.sub(r'[^a-z0-9_]', '_', k.lower())[:MAXKL].strip('_') or 'key'
while nk in out:
nk = (nk[:MAXKL-2] + f'_{len(out)}')
out[nk] = v
return out Type guard
KEY_RE = re.compile(r'^[a-z0-9_]{1,32}$')
def has_valid_keys(meta) -> bool:
return all(isinstance(k, str) and KEY_RE.match(k) for k in meta) Try / catch
try:
validate_user_metadata(meta)
except HTTPException as e:
if e.status_code == 422 and 'is invalid: must be' in e.detail:
meta = normalize_keys(meta); validate_user_metadata(meta)
else:
raise Prevention
- Standardize on snake_case keys in the whole ingestion pipeline.
- Never copy header/camelCase names verbatim into metadata.
- Apply KEY_RE client-side before submit; dedupe after normalization.
When it happens
Trigger: metadata JSON with keys like 'Source-Type', 'file.name', 'category 1', 'ключ', or a 40-char key. Also a non-string JSON key is impossible via json.loads (JSON keys are always strings), so in practice the length/charset predicate is what fails. Applies identically to per-file inner dicts.
Common situations: Copying metadata field names from HTTP headers, file-stat structs, or camelCase ORM fields; LLM-generated metadata keys in natural language ('Document Type'); i18n data with non-ASCII keys; namespaced keys like 'x.custom.label'.
Related errors
- Metadata value for '{key}' exceeds {KB_METADATA_MAX_VALUE_LE
- Metadata array '{key}' exceeds {KB_METADATA_MAX_ARRAY_LENGTH
- Metadata array '{key}' must contain only strings.
- Metadata array entry under '{key}' exceeds {KB_METADATA_MAX_
- Metadata value for '{key}' must be a string, number, bool, o
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/9d36a3af356eb889.
Report an issue: GitHub.