langflow-ai/langflow · warning · HTTPException

Per-file metadata exceeds the {KB_METADATA_MAX_KEYS} file li

Error message

Per-file metadata exceeds the {KB_METADATA_MAX_KEYS} file limit.

What it means

parse_per_file_metadata caps the number of per-file override entries at KB_METADATA_MAX_KEYS = 16 files. A valid-JSON object keyed by filename with more than 16 entries is rejected with 422 before any inner validation runs — mirroring the run-level 16-key cap since each entry expands into per-chunk metadata.

Source

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

    """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

  1. Limit overrides to the files that actually need them (<=16) and put the rest in run-level metadata.
  2. Split the upload into multiple ingest requests, each with <=16 per-file overrides.
  3. Compute the cap from the same constant the server uses (langflow.utils.kb_constants.KB_METADATA_MAX_KEYS) rather than hardcoding, so a client/server mismatch cannot surprise you.
  4. If every file needs distinct metadata, per-request batching by metadata group is usually the cleanest model.

Example fix

# before
per_file = {f.name: meta_for(f) for f in all_files}  # 50 files -> 422

# after
BATCH = 16
for i in range(0, len(all_files), BATCH):
    chunk = all_files[i:i+BATCH]
    submit(files=chunk, per_file_metadata={f.name: meta_for(f) for f in chunk})
Defensive patterns

Strategy: validation

Validate before calling

from langflow.utils.kb_constants import KB_METADATA_MAX_KEYS as MAXK

def batch_per_file(per_file: dict, files: list):
    for i in range(0, len(files), MAXK):
        batch = files[i:i+MAXK]
        yield batch, {f: per_file[f] for f in batch if f in per_file}

Type guard

def within_file_limit(per_file) -> bool:
    return isinstance(per_file, dict) and len(per_file) <= 16

Try / catch

try:
    parse_per_file_metadata(raw)
except HTTPException as e:
    if e.status_code == 422 and 'file limit' in e.detail:
        trimmed = dict(list(per_file.items())[:16])
        raw = json.dumps(trimmed)
        parse_per_file_metadata(raw)
    else:
        raise

Prevention

When it happens

Trigger: per_file_metadata JSON object with 17+ filename keys. Fires before the per-entry checks, so even if every inner dict is perfect, an oversize map is rejected whole. Note the run-level metadata object has the same numeric cap (error 152) but a different message text.

Common situations: Batch-uploading a directory of 50 files with one ingest request and per-file overrides for each; auto-generating overrides for every file in a folder; pipelines that grew incrementally past the cap without noticing.

Related errors


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