{"record":{"id":"d8c1015f61a6dff7","repo":"infiniflow/ragflow","slug":"database-error-file-move","errorCode":null,"errorMessage":"Database error (File move)!","messagePattern":"Database error \\(File move\\)!","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"api/db/services/file_service.py","lineNumber":538,"sourceCode":"            \"tenant_id\": tenant_id,\n            \"created_by\": tenant_id,\n            \"name\": doc[\"name\"],\n            \"type\": doc[\"type\"],\n            \"size\": doc[\"size\"],\n            \"location\": doc[\"location\"],\n            \"source_type\": FileSource.KNOWLEDGEBASE,\n        }\n        cls.save(**file)\n        File2DocumentService.save(id=get_uuid(), file_id=file[\"id\"], document_id=doc[\"id\"])\n\n    @classmethod\n    @DB.connection_context()\n    def move_file(cls, file_ids, folder_id):\n        try:\n            cls.filter_update((cls.model.id << file_ids,), {\"parent_id\": folder_id})\n        except Exception:\n            logger.exception(\"move_file\")\n            raise RuntimeError(\"Database error (File move)!\")\n\n    @classmethod\n    @DB.connection_context()\n    def upload_document(self, kb, file_objs, user_id, src=\"local\", parent_path: str | None = None, parser_config_override: dict | None = None):\n        root_folder = self.get_root_folder(user_id)\n        pf_id = root_folder[\"id\"]\n        self.init_knowledgebase_docs(pf_id, user_id)\n        kb_root_folder = self.get_kb_folder(user_id)\n        kb_folder = self.new_a_file_from_kb(kb.tenant_id, kb.name, kb_root_folder[\"id\"])\n\n        safe_parent_path = sanitize_path(parent_path)\n\n        # Merge parser_config_override with KB parser_config if provided\n        base_parser_config = kb.parser_config or {}\n        if parser_config_override and isinstance(parser_config_override, dict):\n            merged_parser_config = {**base_parser_config, **parser_config_override}\n        else:\n            merged_parser_config = base_parser_config","sourceCodeStart":520,"sourceCodeEnd":556,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/db/services/file_service.py#L520-L556","documentation":"Raised by FileService.move_file when cls.filter_update on the file rows fails. The update sets parent_id = folder_id for all ids in file_ids; any DB exception during that UPDATE (constraint, lock, invalid folder_id) is logged and re-raised as this RuntimeError.","triggerScenarios":"Calling the file-move API with a target folder_id that does not exist or belongs to another tenant (FK violation), moving a very large id list that times out, or moving files while another transaction holds locks on those rows.","commonSituations":"Drag-and-drop in the web UI targeting a folder deleted in another session; API callers passing arbitrary folder ids without validation; concurrent moves/uploads on the same files.","solutions":["Confirm the target folder exists and belongs to the same tenant before calling move_file.","Check logs for the underlying Peewee error (usually IntegrityError or OperationalError).","Retry the move after the concurrent operation finishes if the log shows a lock wait timeout.","Reduce the batch size of file_ids if the update times out on large lists."],"exampleFix":"# before\nFileService.move_file(file_ids, folder_id)\n\n# after\nok, target = FileService.get_by_id(folder_id)\nif not ok or target.type != FileType.FOLDER.value:\n    return json_error_response('target folder not found', code=404)\nFileService.move_file(file_ids, folder_id)","handlingStrategy":"validation","validationCode":"ok, target = FileService.get_by_id(folder_id)\nif not ok:\n    return json_error_response('target folder not found', 404)\nFileService.move_file(file_ids, folder_id)","typeGuard":"def is_valid_move_target(folder_id: str, user_id: str) -> bool:\n    q = FileService.model.select().where(\n        (FileService.model.id == folder_id)\n        & (FileService.model.tenant_id == user_id)\n        & (FileService.model.type == FileType.FOLDER.value)\n    )\n    return q.exists()","tryCatchPattern":"try:\n    FileService.move_file(file_ids, folder_id)\nexcept RuntimeError as e:\n    return json_error_response(f'move failed: {e}', 500)","preventionTips":["Validate the destination folder in the same tenant before calling move APIs.","Refresh folder trees in the UI when a 404/invalid-target response arrives.","Batch large move requests to reduce lock contention."],"tags":["database","update","file-service","move","concurrency"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}