langflow-ai/langflow · warning · HTTPException
Per-file metadata is not valid JSON: {exc.msg}
Error message
Per-file metadata is not valid JSON: {exc.msg} What it means
parse_per_file_metadata json.loads()es the `per_file_metadata` form field; a syntax error in the JSON raises 422 'Per-file metadata is not valid JSON: {parser message}' with the JSONDecodeError chained. This is distinct from error 155 only in field name — the expected shape is {filename: {metadata object}, ...}.
Source
Thrown at src/backend/base/langflow/api/utils/kb_metadata.py:118
msg = f"Metadata is not valid JSON: {exc.msg}"
raise HTTPException(status_code=422, detail=msg) from exc
return validate_user_metadata(decoded)
def parse_per_file_metadata(raw: str | None) -> dict[str, dict[str, Any]]:
"""Decode + validate the ``per_file_metadata`` form field.
Shape: ``{filename: {metadata_dict}, ...}``. Each inner dict goes through
the same validator as run-level metadata, so per-file overrides obey the
same key/value rules. Empty/None → ``{}``.
"""
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
- Construct with json.dumps({fname: meta_dict, ...}).
- Ensure values are dicts BEFORE dumps — json.dumps cannot express a Python dict key that is fine but callers sometimes pass lists of (name, meta) tuples; convert those to a dict first.
- Check the embedded parser message for the exact offset and fix that spot.
- Omit the field entirely when there are no per-file overrides (empty/None -> {}).
Example fix
# before
form.add_field('per_file_metadata', str(per_file)) # repr -> 422
# after
form.add_field('per_file_metadata', json.dumps(per_file)) # e.g. {"a.pdf": {"dept": "fin"}} Defensive patterns
Strategy: validation
Validate before calling
import json
def safe_per_file_field(per_file: dict | None) -> str:
if not per_file:
return ''
assert all(isinstance(k, str) and k and isinstance(v, dict) for k, v in per_file.items())
return json.dumps(per_file) Type guard
def is_valid_per_file_json(raw: str) -> bool:
if not raw:
return True
try:
d = json.loads(raw)
except json.JSONDecodeError:
return False
return isinstance(d, dict) Try / catch
try:
parse_per_file_metadata(raw)
except HTTPException as e:
if e.status_code == 422 and 'Per-file metadata is not valid JSON' in e.detail:
raise ValueError(f'rebuild field with json.dumps: {e.detail}') from e
raise Prevention
- json.dumps the {filename: {...}} dict; never repr() or manual strings.
- Omit the field when no per-file overrides exist.
- Convert list-of-pairs to dict() before serializing.
When it happens
Trigger: per_file_metadata set to a malformed string — unquoted keys, single quotes, trailing commas, or a JSON array of objects instead of an object keyed by filename (the array case parses fine and then fails error 157). Embedded parser message (e.g. 'Expecting value: line 1 column 1') identifies the offset.
Common situations: Building the per-file map by string concatenation ('{' + ','.join(parts) + '}'); double-encoding (a string that is itself a JSON string); clients that serialize {filename: dict} with a non-JSON serializer (Python repr); passing the whole request body as the field by mistake.
Related errors
- Metadata must be a JSON object.
- Metadata is not valid JSON: {exc.msg}
- Per-file metadata must be a JSON object keyed by filename.
- Metadata value for '{key}' exceeds {KB_METADATA_MAX_VALUE_LE
- Metadata array '{key}' exceeds {KB_METADATA_MAX_ARRAY_LENGTH
AI-assisted analysis of langflow-ai/langflow@976ec789d2 (2026-08-14).
Data as JSON: /api/errors/2d93690f5a75f838.
Report an issue: GitHub.