langflow-ai/langflow · warning · HTTPException
Per-file metadata keys must be non-empty filename strings.
Error message
Per-file metadata keys must be non-empty filename strings.
What it means
Inside the per_file_metadata loop, each top-level key must be a non-empty string (a filename). JSON keys from json.loads are always strings, so the reachable condition is the empty-string key '' — 422 'Per-file metadata keys must be non-empty filename strings.' After this, each value must be an object (validated by validate_user_metadata), so a non-dict inner value fails errors 151/153/etc. instead.
Source
Thrown at src/backend/base/langflow/api/utils/kb_metadata.py:129
"""
if not raw:
return {}
try:
decoded = json.loads(raw)
except json.JSONDecodeError as exc:
msg = f"Per-file metadata is not valid JSON: {exc.msg}"
raise HTTPException(status_code=422, detail=msg) from exc
if not isinstance(decoded, dict):
msg = "Per-file metadata must be a JSON object keyed by filename."
raise HTTPException(status_code=422, detail=msg)
if len(decoded) > KB_METADATA_MAX_KEYS:
msg = f"Per-file metadata exceeds the {KB_METADATA_MAX_KEYS} file limit."
raise HTTPException(status_code=422, detail=msg)
out: dict[str, dict[str, Any]] = {}
for filename, file_metadata in decoded.items():
if not isinstance(filename, str) or not filename:
msg = "Per-file metadata keys must be non-empty filename strings."
raise HTTPException(status_code=422, detail=msg)
if not isinstance(file_metadata, dict):
msg = f"Per-file metadata for {filename!r} must be a JSON object."
raise HTTPException(status_code=422, detail=msg)
out[filename] = validate_user_metadata(file_metadata)
return out
View on GitHub (pinned to 976ec789d2)
Solutions
- Skip entries with falsy filenames when building the map: {k: v for k, v in per_file.items() if k}.
- Fix the source: assert the filename is non-empty when you read the upload part, and log/skip rows missing it.
- Match keys exactly to the uploaded files' names (the overrides are looked up per file; an empty key could never match anyway).
- Add a client-side guard: all(isinstance(k, str) and k for k in per_file).
Example fix
# before
per_file[name] = meta # name == '' for missing rows -> 422
# after
if name:
per_file[name] = meta
else:
logger.warning('skipping metadata row without filename') Defensive patterns
Strategy: validation
Validate before calling
def clean_per_file_keys(per_file: dict) -> dict:
dropped = [k for k in per_file if not (isinstance(k, str) and k)]
if dropped:
logger.warning('dropping metadata entries with empty filenames: %r', dropped)
return {k: v for k, v in per_file.items() if isinstance(k, str) and k} Type guard
def has_valid_filename_keys(per_file) -> bool:
return all(isinstance(k, str) and k for k in per_file) Try / catch
try:
parse_per_file_metadata(raw)
except HTTPException as e:
if e.status_code == 422 and 'non-empty filename strings' in e.detail:
per_file = clean_per_file_keys(per_file)
raw = json.dumps(per_file)
parse_per_file_metadata(raw)
else:
raise Prevention
- Guard basename()/filename extraction: skip when the result is empty.
- Validate filename columns in source data before building the map.
- Keys must exactly match the uploaded file names to ever apply — an empty key is always a bug upstream.
When it happens
Trigger: per_file_metadata JSON containing an empty-string key: {"": {"dept": "fin"}}. Typically produced when the filename variable was empty/None at build time (os.path.basename of a directory path, a blank spreadsheet cell, or an unpopulated form field).
Common situations: Path handling bugs: basename('/uploads/') returns ''; iterating rows where the filename column is missing; defaulting an unknown filename to '' instead of skipping; filename lost when a file part is named differently than expected and code falls back to ''.
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/7b083e45d300617f.
Report an issue: GitHub.