{"record":{"id":"1beffbe06921a0ae","repo":"apache/pulsar","slug":"backlog-quota-exceeds-configured-retention-quota-f","errorCode":null,"errorMessage":"Backlog Quota exceeds configured retention quota for namespace. Please increase retention quota and retry","messagePattern":"Backlog Quota exceeds configured retention quota for namespace\\. Please increase retention quota and retry","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java","lineNumber":1891,"sourceCode":"                + \" backlog quota failed because the data validation failed. %s\", namespaceName, e.getMessage()));\n            return CompletableFuture.failedFuture(restException);\n        }\n        return namespaceResources().setPoliciesAsync(namespaceName, policies -> {\n            RetentionPolicies retentionPolicies = policies.retention_policies;\n            final BacklogQuotaType quotaType = backlogQuotaType != null ? backlogQuotaType\n                    : BacklogQuotaType.destination_storage;\n            if (retentionPolicies == null) {\n                policies.backlog_quota_map.put(quotaType, quota);\n                return policies;\n            }\n            // If we have retention policies, we have to check the conflict.\n            BacklogQuota needCheckQuota = null;\n            if (quotaType == BacklogQuotaType.destination_storage) {\n                needCheckQuota = quota;\n            }\n            boolean passCheck = checkBacklogQuota(needCheckQuota, retentionPolicies);\n            if (!passCheck) {\n                throw new RestException(Response.Status.PRECONDITION_FAILED,\n                        \"Backlog Quota exceeds configured retention quota for namespace.\"\n                                + \" Please increase retention quota and retry\");\n            }\n            policies.backlog_quota_map.put(quotaType, quota);\n            return policies;\n        });\n    }\n\n    protected void internalSetRetention(RetentionPolicies retention) {\n        validateRetentionPolicies(retention);\n        validateNamespacePolicyOperation(namespaceName, PolicyName.RETENTION, PolicyOperation.WRITE);\n        validatePoliciesReadOnlyAccess();\n\n        try {\n            Policies policies = namespaceResources().getPolicies(namespaceName)\n                    .orElseThrow(() -> new RestException(Status.NOT_FOUND,\n                    \"Namespace policies does not exist\"));\n            if (!checkQuotas(policies, retention)) {","sourceCodeStart":1873,"sourceCodeEnd":1909,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java#L1873-L1909","documentation":"Thrown when setting a backlog quota (setBacklogQuota) for a namespace whose quota type is destination_storage: the broker validates that the new backlog quota does not exceed the namespace's configured retention quota. The check (checkBacklogQuota) failed, so the update is rejected with HTTP 412 PRECONDITION_FAILED to prevent a backlog policy that conflicts with retention policies.","triggerScenarios":"POST/PUT to /namespaces/{ns}/backlogQuota with a backlogQuota (limit in bytes or retentionTimeInMinutes) larger than the retention quota configured for the namespace while quotaType is destination_storage; setting a very large backlog limit when retention size/time is small.","commonSituations":"Ops teams raising backlog limits to tolerate slow consumers without realizing retention policies cap it; copy-pasted quota configs across namespaces where retention differs; namespace-level retention lowered earlier, making previously valid backlog values invalid.","solutions":["Increase the namespace retention policies (setRetention) so retention quota exceeds the requested backlog quota, then retry","Lower the backlog quota limit/retentionTime to a value at or below the configured retention quota","Check tenant/broker-level defaults that may inject retention limits conflicting with your value","Set both retention and backlog quota in a consistent order: retention first, then backlog quota"],"exampleFix":"// before\nadmin.namespaces().setRetention(\"my-tenant/my-ns\", new RetentionPolicies(1, 10)); // 1MB/10min\nadmin.namespaces().setBacklogQuota(\"my-tenant/my-ns\",\n    new BacklogQuota(1_000_000_000L, RetentionPolicy.producer_exception), BacklogQuotaType.destination_storage); // 412\n// after\nadmin.namespaces().setRetention(\"my-tenant/my-ns\", new RetentionPolicies(2_000_000_000L, 60));\nadmin.namespaces().setBacklogQuota(\"my-tenant/my-ns\",\n    new BacklogQuota(1_000_000_000L, RetentionPolicy.producer_exception), BacklogQuotaType.destination_storage); // passes","handlingStrategy":"validation","validationCode":"RetentionPolicies retention = admin.namespaces().getRetention(ns);\nBacklogQuota quota = new BacklogQuota(limitBytes, policy);\nif (retention != null && quota.getLimitSize() > retention.getRetentionSizeInMB() * 1024L * 1024L) {\n    throw new IllegalArgumentException(\"Backlog quota exceeds retention quota; raise retention first\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    admin.namespaces().setBacklogQuota(ns, quota, BacklogQuotaType.destination_storage);\n} catch (PulsarAdminException.PreconditionFailedException e) {\n    admin.namespaces().setRetention(ns, largerRetention);\n    admin.namespaces().setBacklogQuota(ns, quota, BacklogQuotaType.destination_storage);\n}","preventionTips":["Set retention policies before (or together with) backlog quotas","Keep a documented ratio (retention > backlog) in your config pipeline","Read current retention/backlog via the admin API before changes"],"tags":["http-412","backlog-quota","retention","admin-api"],"backgroundTag":"quota-exceeds-retention","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}