{"record":{"id":"0ff38fb77160c904","repo":"langflow-ai/langflow","slug":"per-file-metadata-keys-must-be-non-empty-filename-0ff38f","errorCode":null,"errorMessage":"Per-file metadata keys must be non-empty filename strings.","messagePattern":"Per-file metadata keys must be non-empty filename strings\\.","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"warning","filePath":"src/backend/base/langflow/api/v1/knowledge_bases.py","lineNumber":1229,"sourceCode":"    \"\"\"\n    _kb_guard = await _guard_kb_action(current_user=current_user, action=KnowledgeBaseAction.INGEST, kb_name=kb_name)\n    _assert_kb_not_memory_base(kb_name, _kb_guard.owner_user)\n    try:\n        # Validate user-supplied metadata before resolving the KB path so a\n        # malformed payload responds with 422 rather than 404 if the KB name\n        # also happens to be wrong.\n        from langflow.api.utils.kb_metadata import (\n            validate_user_metadata as _validate_user_metadata,\n        )\n\n        run_user_metadata: dict[str, Any] = {}\n        if payload.metadata:\n            run_user_metadata = _validate_user_metadata(dict(payload.metadata))\n        per_file_user_metadata: dict[str, dict[str, Any]] = {}\n        if payload.per_file_metadata:\n            for filename, file_meta in payload.per_file_metadata.items():\n                if not isinstance(filename, str) or not filename:\n                    raise HTTPException(\n                        status_code=422,\n                        detail=\"Per-file metadata keys must be non-empty filename strings.\",\n                    )\n                per_file_user_metadata[filename] = _validate_user_metadata(dict(file_meta or {}))\n\n        kb_path = _resolve_kb_path(kb_name, _kb_guard.owner_user)\n        metadata = KBAnalysisHelper.get_metadata(kb_path, fast=False)\n        if not metadata:\n            raise HTTPException(\n                status_code=400,\n                detail=\"Knowledge base missing embedding configuration. Please create a new KB or reconfigure it.\",\n            )\n\n        model_selection = metadata.get(\"model_selection\") or {\n            \"name\": metadata.get(\"embedding_model\"),\n            \"provider\": metadata.get(\"embedding_provider\"),\n        }\n        if not model_selection.get(\"name\") or not model_selection.get(\"provider\"):","sourceCodeStart":1211,"sourceCodeEnd":1247,"githubUrl":"https://github.com/langflow-ai/langflow/blob/976ec789d2886a86de109c044d089d68e96c9a35/src/backend/base/langflow/api/v1/knowledge_bases.py#L1211-L1247","documentation":"A 422 from the folder-ingest endpoint when the per_file_metadata mapping has a key that is not a non-empty string. Keys are filenames used to attach metadata to specific ingested files, so empty or non-string keys are rejected during request validation.","triggerScenarios":"POST /api/v1/knowledge_bases/{kb_name}/ingest/folder with a JSON body whose per_file_metadata object contains a key like \"\" (empty string) or a non-string key (possible when building the dict with int/None keys before serializing, or hand-writing malformed JSON).","commonSituations":"Client code constructing per_file_metadata programmatically with Path objects coerced badly, typos in hand-written payloads, or empty-string filenames from upstream file listing code.","solutions":["Ensure every key in per_file_metadata is a non-empty filename string exactly matching an ingested file's name.","Sanitize the dict client-side before sending: drop or rename empty/None keys.","If filenames come from os.walk output, filter out non-string or empty entries."],"exampleFix":"# before\nper_file = {\"\": {...}, \"report.pdf\": {...}}\n\n# after\nper_file = {name: meta for name, meta in per_file.items() if isinstance(name, str) and name}","handlingStrategy":"validation","validationCode":"def sanitize_per_file_metadata(per_file: dict) -> dict[str, dict]:\n    return {\n        str(name): meta or {}\n        for name, meta in per_file.items()\n        if isinstance(name, str) and name\n    }","typeGuard":"def is_valid_per_file_metadata(d: object) -> bool:\n    if not isinstance(d, dict):\n        return False\n    return all(isinstance(k, str) and bool(k) for k in d)","tryCatchPattern":null,"preventionTips":["Build per_file_metadata only from filesystem-derived filename strings.","Filter empty-string or None keys before serializing the request body.","Add a unit test asserting every key of the payload is a non-empty string."],"tags":["knowledge-base","validation","metadata","http-422"],"backgroundTag":null,"analyzedSha":"976ec789d2886a86de109c044d089d68e96c9a35","analyzedAt":"2026-08-14T18:23:12.227Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}