{"record":{"id":"b573d9c3039b2b9b","repo":"langgenius/dify","slug":"doc-metadata-must-be-a-dictionary","errorCode":null,"errorMessage":"doc_metadata must be a dictionary.","messagePattern":"doc_metadata must be a dictionary\\.","errorType":"validation","errorClass":"ValueError","httpStatus":500,"severity":"error","filePath":"api/controllers/console/datasets/datasets_document.py","lineNumber":1315,"sourceCode":"        dataset_id_str = str(dataset_id)\n        document_id_str = str(document_id)\n        document = self.get_document(session, dataset_id_str, document_id_str, current_user, current_tenant_id)\n\n        doc_type = req_data.doc_type\n        doc_metadata = req_data.doc_metadata\n\n        # The role of the current user in the ta table must be admin, owner, dataset_operator, or editor\n        if not current_user.is_dataset_editor:\n            raise Forbidden()\n\n        if doc_type is None or doc_metadata is None:\n            raise ValueError(\"Both doc_type and doc_metadata must be provided.\")\n\n        if doc_type not in DocumentService.DOCUMENT_METADATA_SCHEMA:\n            raise ValueError(\"Invalid doc_type.\")\n\n        if not isinstance(doc_metadata, dict):\n            raise ValueError(\"doc_metadata must be a dictionary.\")\n        metadata_schema: dict[str, Any] = cast(dict[str, Any], DocumentService.DOCUMENT_METADATA_SCHEMA[doc_type])\n\n        document.doc_metadata = {}\n        if doc_type == \"others\":\n            document.doc_metadata = doc_metadata\n        else:\n            for key, value_type in metadata_schema.items():\n                value = doc_metadata.get(key)\n                if value is not None and isinstance(value, value_type):\n                    document.doc_metadata[key] = value\n\n        document.doc_type = doc_type\n        document.updated_at = naive_utc_now()\n\n        return SimpleResultMessageResponse(result=\"success\", message=\"Document metadata updated.\").model_dump(\n            mode=\"json\"\n        ), 200\n","sourceCodeStart":1297,"sourceCodeEnd":1333,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/datasets/datasets_document.py#L1297-L1333","documentation":"Raised in the metadata PUT handler when doc_metadata is not a dict (datasets_document.py:1314). DocumentMetadataUpdatePayload types doc_metadata as Any, so the route accepts any JSON value and the isinstance(doc_metadata, dict) check fails post-parse. Same controller defect: ValueError becomes HTTP 500, not 400.","triggerScenarios":"PUT .../metadata with doc_metadata as a JSON string (\"title=foo\"), a list, a number, or null; the isinstance check at line 1314 rejects it.","commonSituations":"Client serializing the metadata object to a string before sending; sending an array of key-value pairs instead of an object; SDK generated with the wrong field type.","solutions":["Send doc_metadata as a JSON object (dict) whose keys/values match the doc_type schema.","Server-side fix: type the payload field as dict[str, Any] so Pydantic rejects non-objects with a 422."],"exampleFix":"# before\nclass DocumentMetadataUpdatePayload(BaseModel):\n    doc_type: str | None = None\n    doc_metadata: Any = None\n# after\nclass DocumentMetadataUpdatePayload(BaseModel):\n    doc_type: str\n    doc_metadata: dict[str, Any]","handlingStrategy":"type-guard","validationCode":"if not isinstance(doc_metadata, dict):\n    raise TypeError(\"doc_metadata must be a JSON object (dict), got \" + type(doc_metadata).__name__)","typeGuard":"def is_metadata_dict(doc_metadata) -> bool:\n    return isinstance(doc_metadata, dict)","tryCatchPattern":"try:\n    console.update_document_metadata(dataset_id, document_id, payload)\nexcept HTTPError as e:\n    if e.response.status_code >= 500 and \"must be a dictionary\" in e.response.json().get(\"message\", \"\"):\n        payload[\"doc_metadata\"] = dict(payload[\"doc_metadata\"])  # coerce and retry\n        console.update_document_metadata(dataset_id, document_id, payload)\n    else:\n        raise","preventionTips":["Serialize doc_metadata as a JSON object, never a string or list.","Add a client-side isinstance check before sending."],"tags":["metadata","validation","bug","knowledge"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}