{"record":{"id":"3dfc10d20d92c7de","repo":"langgenius/dify","slug":"the-number-of-documents-has-reached-the-limit-of-y","errorCode":null,"errorMessage":"The number of documents has reached the limit of your subscription.","messagePattern":"The number of documents has reached the limit of your subscription\\.","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"api/controllers/console/wraps.py","lineNumber":210,"sourceCode":"                    )\n                return view(*args, **kwargs)\n\n            features = FeatureService.get_features(current_tenant_id, exclude_vector_space=True)\n            if features.billing.enabled:\n                members = features.members\n                apps = features.apps\n                documents_upload_quota = features.documents_upload_quota\n                annotation_quota_limit = features.annotation_quota_limit\n                if resource == \"members\" and 0 < members.limit <= members.size:\n                    abort(403, \"The number of members has reached the limit of your subscription.\")\n                elif resource == \"apps\" and 0 < apps.limit <= apps.size:\n                    abort(403, \"The number of apps has reached the limit of your subscription.\")\n                elif resource == \"documents\" and 0 < documents_upload_quota.limit <= documents_upload_quota.size:\n                    # The api of file upload is used in the multiple places,\n                    # so we need to check the source of the request from datasets\n                    source = request.args.get(\"source\") or request.form.get(\"source\")\n                    if source == \"datasets\":\n                        abort(403, \"The number of documents has reached the limit of your subscription.\")\n                    else:\n                        return view(*args, **kwargs)\n                elif resource == \"workspace_custom\" and not features.can_replace_logo:\n                    abort(403, \"The workspace custom feature has reached the limit of your subscription.\")\n                elif resource == \"annotation\" and 0 < annotation_quota_limit.limit < annotation_quota_limit.size:\n                    abort(403, \"The annotation quota has reached the limit of your subscription.\")\n                else:\n                    return view(*args, **kwargs)\n\n            return view(*args, **kwargs)\n\n        return decorated\n\n    return interceptor\n\n\ndef cloud_edition_billing_knowledge_limit_check[**P, R](\n    resource: str,","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/controllers/console/wraps.py#L192-L228","documentation":"HTTP 403 from `cloud_edition_billing_resource_check(\"documents\")`, fired only when the upload `source` is `datasets`. When `resource == \"documents\"` and `0 < documents_upload_quota.limit <= documents_upload_quota.size`, and `request.args/form.get(\"source\") == \"datasets\"`, the decorator aborts with `The number of documents has reached the limit of your subscription.` Non-datasets uploads are allowed to pass through.","triggerScenarios":"Uploading a document to a dataset (`source=datasets`) on a tenant whose document upload count has reached the plan quota. Uploads without `source=datasets` deliberately bypass this check.","commonSituations":"Free-plan workspace hitting the documents quota; batch ingest from the datasets UI; the upload API being reused from another flow without the `source=datasets` marker (then it silently bypasses the check).","solutions":["Upgrade the workspace plan to raise the document quota.","Delete stale documents to bring `size` under `limit`.","Surface the quota (`documents_upload_quota`) in the datasets UI and block uploads at the ceiling.","Always send `source=datasets` from dataset uploads so the quota is enforced consistently."],"exampleFix":"// before\nfetch('/files/upload', { body: form })  // omitting source bypasses quota\n// after\nform.append('source', 'datasets')\nfetch('/files/upload', { body: form })  // quota enforced; show upgrade CTA on 403","handlingStrategy":"validation","validationCode":"from services.feature_service import FeatureService\n\n_, tenant_id = current_account_with_tenant()\nfeatures = FeatureService.get_features(tenant_id, exclude_vector_space=True)\nq = features.documents_upload_quota\n\ndef can_upload_dataset_doc() -> bool:\n    return not (q.limit > 0 and q.size >= q.limit)\n\nif not can_upload_dataset_doc():\n    # surface upgrade prompt instead of uploading to datasets\n    ...","typeGuard":"def under_doc_quota(limit: int, size: int) -> bool:\n    return not (limit > 0 and size >= limit)","tryCatchPattern":"try:\n    # always send source=datasets from dataset uploads\n    resp = client.post(\"/files/upload\", files=..., data={\"source\": \"datasets\"})\nexcept HTTPError as err:\n    if err.response.status_code == 403 and \"documents\" in err.response.text:\n        # document quota reached — upgrade or clean up\n        ...\n    raise","preventionTips":["Always send source=datasets from dataset uploads so the quota is enforced consistently.","Show document quota in the datasets UI; block uploads at the ceiling.","Delete stale documents to free quota.","Upgrade the plan to raise the document quota."],"tags":["billing","quota","documents","datasets","http-403"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}