langflow-ai/langflow · error · HTTPException

Per-file metadata for {filename!r} must be a JSON object.

Error message

Per-file metadata for {filename!r} must be a JSON object.

What it means

Raised by validate_file_metadata_map in the knowledge-base upload API when the per-file metadata payload is a JSON object overall, but one of its values (the metadata for a specific filename) is not itself a JSON object. The endpoint validates the file_metadata_map before processing uploads and rejects the whole request with HTTP 422. Each filename key must map to a dict of key/value metadata pairs.

Source

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

    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

  1. Fix the payload so every filename key maps to a JSON object of metadata pairs: {"<filename>": {"key": "value", ...}}
  2. Verify you are not double-stringifying: if you json.dumps the inner metadata before sending, decode it client-side first
  3. Check the other 422 guards in the same validator (top-level must be an object, <= KB_METADATA_MAX_KEYS entries, non-empty filename keys) if the error persists

Example fix

// before
file_metadata_map = {"report.pdf": "source=legal"}
// after
file_metadata_map = {"report.pdf": {"source": "legal"}}
Defensive patterns

Strategy: validation

Validate before calling

def is_valid_file_metadata_map(payload: str | dict) -> bool:
    import json
    decoded = json.loads(payload) if isinstance(payload, str) else payload
    return (
        isinstance(decoded, dict)
        and decoded
        and all(
            isinstance(k, str) and k and isinstance(v, dict)
            for k, v in decoded.items()
        )
    )

Type guard

def is_file_metadata_map(v: object) -> bool:
    return isinstance(v, dict) and all(
        isinstance(k, str) and k and isinstance(m, dict) for k, m in v.items()
    )

Try / catch

try:
    resp = client.post(kb_upload_url, files=files, data={"file_metadata_map": json.dumps(mm)})
except HTTPStatusError as e:
    if e.response.status_code == 422:
        detail = e.response.json()["detail"]
        if "must be a JSON object" in detail:
            fix_and_retry(mm)  # normalize offending entry to a dict
        else:
            raise
    else:
        raise

Prevention

When it happens

Trigger: POST to a KB file-upload endpoint with a JSON file_metadata_map whose decoded top-level value is a dict, but where at least one filename entry maps to a string, number, list, or null instead of an object (e.g. {"report.pdf": "category: docs"} or {"a.txt": ["tag"]}).

Common situations: Clients that send metadata as a flat string, a JSON-encoded string inside a string, or reuse a per-file metadata schema from an older API version that accepted scalars; copy-pasting the single-file metadata object directly as the value instead of nesting it under the filename key.

Related errors


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