{"record":{"id":"0c3c1d5ce4535e1e","repo":"infiniflow/ragflow","slug":"exceed-the-maximum-file-number-of-a-free-user","errorCode":null,"errorMessage":"Exceed the maximum file number of a free user!","messagePattern":"Exceed the maximum file number of a free user!","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"api/db/services/document_service.py","lineNumber":125,"sourceCode":"\n        count = docs.count()\n        docs = docs.paginate(page_number, items_per_page)\n\n        docs_list = list(docs.dicts())\n        doc_ids_on_page = [doc[\"id\"] for doc in docs_list]\n        metadata_map = DocMetadataService.get_metadata_for_documents(doc_ids_on_page, kb_id) if doc_ids_on_page else {}\n        for doc in docs_list:\n            doc[\"meta_fields\"] = metadata_map.get(doc[\"id\"], {})\n        return docs_list, count\n\n    @classmethod\n    @DB.connection_context()\n    def check_doc_health(cls, tenant_id: str, filename):\n        import os\n\n        MAX_FILE_NUM_PER_USER = int(os.environ.get(\"MAX_FILE_NUM_PER_USER\", 0))\n        if 0 < MAX_FILE_NUM_PER_USER <= DocumentService.get_doc_count(tenant_id):\n            raise RuntimeError(\"Exceed the maximum file number of a free user!\")\n        if len(filename.encode(\"utf-8\")) > FILE_NAME_LEN_LIMIT:\n            raise RuntimeError(\"Exceed the maximum length of file name!\")\n        return True\n\n    @classmethod\n    @DB.connection_context()\n    def get_by_kb_id(cls, kb_id, page_number, items_per_page, orderby, desc, keywords, run_status, types, suffix, name=None, doc_ids=None, return_empty_metadata=False):\n        fields = cls.get_cls_model_fields()\n        if keywords:\n            docs = (\n                cls.model.select(*[*fields, UserCanvas.title.alias(\"pipeline_name\"), User.nickname])\n                .join(File2Document, on=(File2Document.document_id == cls.model.id))\n                .join(File, on=(File.id == File2Document.file_id))\n                .join(UserCanvas, on=(cls.model.pipeline_id == UserCanvas.id), join_type=JOIN.LEFT_OUTER)\n                .join(User, on=(cls.model.created_by == User.id), join_type=JOIN.LEFT_OUTER)\n                .where((cls.model.kb_id == kb_id), (fn.LOWER(cls.model.name).contains(keywords.lower())))\n            )\n        else:","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/infiniflow/ragflow/blob/554fb1133ac3861732235ad9c377eb5e0a770665/api/db/services/document_service.py#L107-L143","documentation":"RuntimeError from DocumentService.check_doc_health when the environment variable MAX_FILE_NUM_PER_USER is set to a positive number and the tenant's existing document count has reached it. It is the free-tier file-count quota enforcement at upload time.","triggerScenarios":"Uploading a document while MAX_FILE_NUM_PER_USER > 0 and DocumentService.get_doc_count(tenant_id) >= that limit (env default 0 disables the check).","commonSituations":"SaaS/multi-tenant deployments capping free users; raising the env var expectation after deleting documents that are still counted (soft-deleted rows); shared dev environment hitting the cap during bulk tests.","solutions":["Delete unneeded documents (and ensure they are purged from the count) or upgrade the user's quota.","If you operate the deployment, raise or unset MAX_FILE_NUM_PER_USER.","Check the count first via get_doc_count before uploading to give users an early warning."],"exampleFix":"# before: MAX_FILE_NUM_PER_USER=100 and user has 100 docs, upload proceeds and fails\n# after (operator)\n# docker/...: - MAX_FILE_NUM_PER_USER=0  (disable) or a higher cap","handlingStrategy":"validation","validationCode":"import os\nfrom api.db.services.document_service import DocumentService\n\nmax_n = int(os.environ.get('MAX_FILE_NUM_PER_USER', 0) or 0)\nif 0 < max_n <= DocumentService.get_doc_count(tenant_id):\n    raise PermissionError(f'file quota ({max_n}) reached — delete documents first')","typeGuard":null,"tryCatchPattern":"try:\n    DocumentService.check_doc_health(tenant_id, filename)\nexcept RuntimeError as e:\n    if 'maximum file number' in str(e):\n        notify_user_quota_reached()  # block upload in UI instead of failing\n    else:\n        raise","preventionTips":["Show a live file-count/quota indicator in the upload UI.","Purge soft-deleted documents so the counted total matches what users see."],"tags":["quota","upload","environment-variable","free-tier"],"backgroundTag":null,"analyzedSha":"554fb1133ac3861732235ad9c377eb5e0a770665","analyzedAt":"2026-08-15T09:20:16.380Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}