apache/pulsar · error · ParameterException

Quota type of 'destination_storage' needs a size limit

Error message

Quota type of 'destination_storage' needs a size limit

What it means

When the backlog quota type is destination_storage, the quota is defined by a storage size, so --limit-size is mandatory. The CLI throws this ParameterException if limit is null, because a destination_storage quota without a size would be meaningless.

Source

Thrown at pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CmdNamespaces.java:1325

            } catch (IllegalArgumentException e) {
                throw new ParameterException(String.format("Invalid retention policy type '%s'. Valid options are: %s",
                        policyStr, Arrays.toString(BacklogQuota.RetentionPolicy.values())));
            }

            try {
                backlogQuotaType = BacklogQuota.BacklogQuotaType.valueOf(backlogQuotaTypeStr);
            } catch (IllegalArgumentException e) {
                throw new ParameterException(String.format("Invalid backlog quota type '%s'. Valid options are: %s",
                        backlogQuotaTypeStr, Arrays.toString(BacklogQuota.BacklogQuotaType.values())));
            }

            String namespace = validateNamespace(namespaceName);

            BacklogQuota.Builder builder = BacklogQuota.builder().retentionPolicy(policy);
            if (backlogQuotaType == BacklogQuota.BacklogQuotaType.destination_storage) {
                // set quota by storage size
                if (limit == null) {
                    throw new ParameterException("Quota type of 'destination_storage' needs a size limit");
                }
                builder.limitSize(limit);
            } else {
                // set quota by time
                if (limitTimeInSec == null) {
                    throw new ParameterException("Quota type of 'message_age' needs a time limit");
                }
                builder.limitTime(limitTimeInSec.intValue());
            }
            getAdmin().namespaces().setBacklogQuota(namespace, builder.build(), backlogQuotaType);
        }
    }

    @Command(description = "Remove a backlog quota policy from a namespace")
    private class RemoveBacklogQuota extends CliCommand {
        @Parameters(description = "tenant/namespace", arity = "1")
        private String namespaceName;

View on GitHub (pinned to 820761864e)

Solutions

  1. Add --limit-size (e.g. --limit-size 10G) to the command
  2. Or, if you meant a time-based quota, change --backlog-quota-type to message_age and pass --limit-time instead

Example fix

// before
pulsar-admin namespaces set-backlog-quota my-tenant/my-ns --backlog-quota-type destination_storage --retention-policy producer_exception
// after
pulsar-admin namespaces set-backlog-quota my-tenant/my-ns --backlog-quota-type destination_storage --retention-policy producer_exception --limit-size 10G
Defensive patterns

Strategy: validation

Validate before calling

// shell guard
if [ "$QUOTA_TYPE" = "destination_storage" ] && [ -z "$LIMIT_SIZE" ]; then
  echo "--limit-size required for destination_storage" >&2; exit 1;
fi

Type guard

// pseudo: pair type with its required limit
if ("destination_storage".equals(type) && limitSize == null) {
    throw new IllegalArgumentException("--limit-size required for destination_storage");
}

Try / catch

try {
    admin.namespaces().setBacklogQuota(ns, quota, type);
} catch (IllegalArgumentException e) {
    // re-issue the command with --limit-size
}

Prevention

When it happens

Trigger: Running `pulsar-admin namespaces set-backlog-quota <ns> --backlog-quota-type destination_storage --retention-policy <policy>` without --limit-size (limit == null), or with a time flag only.

Common situations: Users copying the message_age example but switching the type to destination_storage; automation where --limit-size is only appended for one quota type branch; forgetting the flag when converting from time-based to size-based quotas.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/1b3960878c0b3267. Report an issue: GitHub.