apache/pulsar · warning · IllegalArgumentException
couldn't find subscription
Error message
couldn't find subscription
What it means
When revoking subscription permissions, updateSubscriptionPermissionAsync removes the role set if it exists; if the subscription has no entry (or the roles set doesn't contain the role) in the policies, it throws IllegalArgumentException('couldn't find subscription'). This is a client/consistency error: the caller asked to revoke from a subscription that has no recorded permissions.
Source
Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/broker/authorization/PulsarAuthorizationProvider.java:467
throw new IllegalStateException("policies are in readonly mode");
}
return pulsarResources.getNamespaceResources()
.setPoliciesAsync(namespace, policies -> {
if (remove) {
Set<String> subscriptionAuth =
policies.auth_policies.getSubscriptionAuthentication().get(subscriptionName);
if (subscriptionAuth != null) {
subscriptionAuth.removeAll(roles);
if (subscriptionAuth.isEmpty()) {
policies.auth_policies.getSubscriptionAuthentication().remove(subscriptionName);
}
} else {
log.info()
.attr("namespace", namespace)
.attr("role", roles)
.attr("sub", subscriptionName)
.log("Couldn't find role while revoking for sub");
throw new IllegalArgumentException("couldn't find subscription");
}
} else {
policies.auth_policies.getSubscriptionAuthentication().put(subscriptionName, roles);
}
return policies;
}).whenComplete((__, throwable) -> {
if (throwable != null) {
log.error()
.attr("subscriptionName", subscriptionName)
.attr("role", roles)
.attr("namespace", namespace)
.exception(throwable)
.log("Failed to set permissions for role on namespace");
} else {
log.info()
.attr("namespace", namespace)
.attr("role", roles)
.attr("sub", subscriptionName)View on GitHub (pinned to 820761864e)
Solutions
- Check GET /namespaces/{ns}/permissions/subscription first and skip the revoke if the subscription/role is absent
- Treat the failed future as idempotent success in the caller if the goal is 'role no longer has access'
- Correct the subscription name and retry
- Handle races by catching IllegalArgumentException from the revoke and continuing
Example fix
// before
await authorization.revokeSubscriptionPermissionAsync(ns, sub, role);
// after
Map<String, Set<String>> subs =
await authorization.getSubscriptionPermissionsAsync(ns);
if (subs.containsKey(sub) && subs.get(sub).contains(role)) {
await authorization.revokeSubscriptionPermissionAsync(ns, sub, role);
} Defensive patterns
Strategy: validation
Validate before calling
Map<String, Set<String>> subPerms =
authorization.getSubscriptionPermissionsAsync(namespace).get();
if (!subPerms.containsKey(subscriptionName)
|| !subPerms.get(subscriptionName).contains(role)) {
return; // nothing to revoke
} Try / catch
try {
revokeSubFuture.get();
} catch (ExecutionException e) {
if (e.getCause() instanceof IllegalArgumentException) {
// treat as idempotent no-op
}
} Prevention
- Read current subscription permissions before revoking
- Make revoke operations idempotent in callers
- Validate subscription names against the namespace's policies
- Guard against double-revokes from client retries
When it happens
Trigger: revokeSubscriptionPermissionAsync on a subscription that was never granted permissions, was already fully revoked, or whose policies entry was removed concurrently.
Common situations: Double-revoke from retries or two admins; revoking against a renamed subscription; stale client view of existing subscription permissions; typo in subscription name.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Unauthorized to validateBothSuperuserAndBrokerOperation for
- Unauthorized to validateBrokerOperation for originalPrincipa
- Namespace does not exist
- Subscription not found
- Subscription has active connected consumers
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/331891a80033fb8c.
Report an issue: GitHub.