apolloconfig/apollo · error · BadRequestException
Invalid user token status:%s
Error message
Invalid user token status:%s
What it means
Thrown by UserTokenService.normalizeStatus() when the status query parameter passed to the admin token-list endpoint does not match one of the allowed values: 'all', 'active', 'expired', or 'revoked' (case-insensitive after trim). The value is compared against the four TOKEN_STATUS_* constants. The resulting BadRequestException maps to HTTP 400. The %s placeholder is filled with the raw input value via Guava Strings.lenientFormat.
Source
Thrown at apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/UserTokenService.java:291
return userToken;
}
private UserToken findToken(long tokenId) {
return userTokenRepository.findById(tokenId)
.orElseThrow(() -> new NotFoundException("user token not found for id:%s", tokenId));
}
private String normalizeStatus(String status) {
if (StringUtils.isBlank(status)) {
return TOKEN_STATUS_ALL;
}
String normalizedStatus = status.trim().toLowerCase(Locale.ROOT);
if (TOKEN_STATUS_ALL.equals(normalizedStatus) || TOKEN_STATUS_ACTIVE.equals(normalizedStatus)
|| TOKEN_STATUS_EXPIRED.equals(normalizedStatus)
|| TOKEN_STATUS_REVOKED.equals(normalizedStatus)) {
return normalizedStatus;
}
throw new BadRequestException("Invalid user token status:%s", status);
}
private boolean matchesStatus(UserToken userToken, String status, Date now) {
return TOKEN_STATUS_ALL.equals(status) || status.equals(resolveStatus(userToken, now));
}
private String resolveStatus(UserToken userToken, Date now) {
if (userToken.getRevokedAt() != null) {
return TOKEN_STATUS_REVOKED;
}
if (userToken.getExpires() != null && !userToken.getExpires().after(now)) {
return TOKEN_STATUS_EXPIRED;
}
return TOKEN_STATUS_ACTIVE;
}
private UserTokenScope buildScope(UserTokenCreateRequest request) {
UserTokenScope scope = new UserTokenScope();View on GitHub (pinned to d95fc18d11)
Solutions
- Pass one of: 'all', 'active', 'expired', 'revoked' (or null/blank to default to 'all').
- If calling via REST, omit the status query param entirely — normalizeStatus returns TOKEN_STATUS_ALL for blank input.
- If extending the status taxonomy, add the new constant and update the if-chain in normalizeStatus().
Example fix
// before
userTokenService.findUserTokensForAdmin("alice", "inactive");
// after
userTokenService.findUserTokensForAdmin("alice", "all"); Defensive patterns
Strategy: validation
Validate before calling
private static final Set<String> VALID_STATUSES = Set.of("all", "active", "expired", "revoked");
String normalized = status == null ? "all" : status.trim().toLowerCase(Locale.ROOT);
if (!VALID_STATUSES.contains(normalized)) {
throw new IllegalArgumentException("Invalid status: " + status + ". Use one of: " + VALID_STATUSES);
}
userTokenService.findUserTokensForAdmin(userId, normalized); Type guard
static boolean isValidTokenStatus(String status) {
if (status == null || status.isBlank()) return true;
return Set.of("all", "active", "expired", "revoked")
.contains(status.trim().toLowerCase(Locale.ROOT));
} Try / catch
try {
userTokenService.findUserTokensForAdmin(userId, status);
} catch (BadRequestException e) {
if (e.getMessage().contains("Invalid user token status")) {
return Response.status(400).entity("Allowed statuses: all, active, expired, revoked").build();
}
throw e;
} Prevention
- Use a dropdown with hardcoded status options (all/active/expired/revoked) in the UI.
- Omit the status parameter entirely to default to 'all'.
When it happens
Trigger: Calling findUserTokensForAdmin(userId, status) — the admin API for listing user tokens — with a status argument that is not blank and not one of 'all'/'active'/'expired'/'revoked'. For example, passing status='invalid', status='ACTIVE ' (trailing space is fine since trim+lowercase is applied, so only truly unrecognized values trigger it), or a typo like 'acitve'.
Common situations: Frontend dropdown or URL query parameter for the token admin page sends a status filter value that drifts from the allowed set. A client upgrade changes the vocabulary but the server isn't updated, or vice versa. Manual API testing with an arbitrary string.
Related errors
- Invalid user token operation:%s
- Token name can not be blank
- Token namespace scope can not be null
- Token expires must be in the future
- Token expires exceeds max allowed days:%s
AI-assisted analysis of apolloconfig/apollo@d95fc18d11 (2026-08-14).
Data as JSON: /api/errors/c36ecbe97635663a.
Report an issue: GitHub.