{"record":{"id":"798938df091747f4","repo":"langgenius/dify","slug":"both-doc-type-and-doc-metadata-must-be-provided","errorCode":null,"errorMessage":"Both doc_type and doc_metadata must be provided.","messagePattern":"Both doc_type and doc_metadata must be provided\\.","errorType":"validation","errorClass":"ValueError","httpStatus":500,"severity":"error","filePath":"api/controllers/console/datasets/datasets_document.py","lineNumber":1309,"sourceCode":"        session: Session,\n        current_tenant_id: str,\n        current_user: Account,\n        dataset_id: UUID,\n        document_id: UUID,\n    ):\n        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","sourceCodeStart":1291,"sourceCodeEnd":1327,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/datasets/datasets_document.py#L1291-L1327","documentation":"Raised in the metadata PUT handler when doc_type or doc_metadata is None (datasets_document.py:1308). Because ValueError is not a BaseHTTPException, it escapes as an HTTP 500 rather than a clean 400 - this is a controller defect. DocumentMetadataUpdatePayload declares both fields optional (str | None and Any = None), so the route accepts the partial body and fails post-parse.","triggerScenarios":"PUT .../documents/{id}/metadata with body {} , {\"doc_type\":\"book\"} (missing doc_metadata), or {\"doc_metadata\":{...}} (missing doc_type); the None-check at line 1308 raises ValueError.","commonSituations":"Frontend sending a partial update intending patch semantics on a PUT; SDK generated from the optional schema sending only one field; client assuming the server applies defaults.","solutions":["Include both doc_type and doc_metadata in the request body.","Server-side fix: make DocumentMetadataUpdatePayload require both fields, or raise InvalidMetadataError instead of ValueError to return a proper 400."],"exampleFix":"# before\nif doc_type is None or doc_metadata is None:\n    raise ValueError(\"Both doc_type and doc_metadata must be provided.\")\n# after\nif doc_type is None or doc_metadata is None:\n    raise InvalidMetadataError(\"Both doc_type and doc_metadata must be provided.\")\n# and make the payload require both fields:\nclass DocumentMetadataUpdatePayload(BaseModel):\n    doc_type: str\n    doc_metadata: dict[str, Any]","handlingStrategy":"validation","validationCode":"# Validate payload before sending: both fields required\npayload = {\"doc_type\": doc_type, \"doc_metadata\": doc_metadata}\nif payload[\"doc_type\"] is None or payload[\"doc_metadata\"] is None:\n    raise ValueError(\"Both doc_type and doc_metadata must be provided in the request body.\")","typeGuard":"def is_complete_metadata_payload(doc_type, doc_metadata) -> bool:\n    return doc_type is not None and doc_metadata is not None","tryCatchPattern":"try:\n    console.update_document_metadata(dataset_id, document_id, payload)\nexcept HTTPError as e:\n    if e.response.status_code >= 500:\n        # ValueError currently surfaces as 500; validate payload and retry\n        ensure_both_fields(payload)\n    else:\n        raise","preventionTips":["Always include both doc_type and doc_metadata in the PUT body.","Treat this as a server bug: prefer patching the controller to raise InvalidMetadataError (400)."],"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"}