{"record":{"id":"c36ecbe97635663a","repo":"apolloconfig/apollo","slug":"invalid-user-token-status-s","errorCode":null,"errorMessage":"Invalid user token status:%s","messagePattern":"Invalid user token status:(.+?)","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/UserTokenService.java","lineNumber":291,"sourceCode":"    return userToken;\n  }\n\n  private UserToken findToken(long tokenId) {\n    return userTokenRepository.findById(tokenId)\n        .orElseThrow(() -> new NotFoundException(\"user token not found for id:%s\", tokenId));\n  }\n\n  private String normalizeStatus(String status) {\n    if (StringUtils.isBlank(status)) {\n      return TOKEN_STATUS_ALL;\n    }\n    String normalizedStatus = status.trim().toLowerCase(Locale.ROOT);\n    if (TOKEN_STATUS_ALL.equals(normalizedStatus) || TOKEN_STATUS_ACTIVE.equals(normalizedStatus)\n        || TOKEN_STATUS_EXPIRED.equals(normalizedStatus)\n        || TOKEN_STATUS_REVOKED.equals(normalizedStatus)) {\n      return normalizedStatus;\n    }\n    throw new BadRequestException(\"Invalid user token status:%s\", status);\n  }\n\n  private boolean matchesStatus(UserToken userToken, String status, Date now) {\n    return TOKEN_STATUS_ALL.equals(status) || status.equals(resolveStatus(userToken, now));\n  }\n\n  private String resolveStatus(UserToken userToken, Date now) {\n    if (userToken.getRevokedAt() != null) {\n      return TOKEN_STATUS_REVOKED;\n    }\n    if (userToken.getExpires() != null && !userToken.getExpires().after(now)) {\n      return TOKEN_STATUS_EXPIRED;\n    }\n    return TOKEN_STATUS_ACTIVE;\n  }\n\n  private UserTokenScope buildScope(UserTokenCreateRequest request) {\n    UserTokenScope scope = new UserTokenScope();","sourceCodeStart":273,"sourceCodeEnd":309,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/UserTokenService.java#L273-L309","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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.","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()."],"exampleFix":"// before\nuserTokenService.findUserTokensForAdmin(\"alice\", \"inactive\");\n// after\nuserTokenService.findUserTokensForAdmin(\"alice\", \"all\");","handlingStrategy":"validation","validationCode":"private static final Set<String> VALID_STATUSES = Set.of(\"all\", \"active\", \"expired\", \"revoked\");\nString normalized = status == null ? \"all\" : status.trim().toLowerCase(Locale.ROOT);\nif (!VALID_STATUSES.contains(normalized)) {\n    throw new IllegalArgumentException(\"Invalid status: \" + status + \". Use one of: \" + VALID_STATUSES);\n}\nuserTokenService.findUserTokensForAdmin(userId, normalized);","typeGuard":"static boolean isValidTokenStatus(String status) {\n    if (status == null || status.isBlank()) return true;\n    return Set.of(\"all\", \"active\", \"expired\", \"revoked\")\n        .contains(status.trim().toLowerCase(Locale.ROOT));\n}","tryCatchPattern":"try {\n    userTokenService.findUserTokensForAdmin(userId, status);\n} catch (BadRequestException e) {\n    if (e.getMessage().contains(\"Invalid user token status\")) {\n        return Response.status(400).entity(\"Allowed statuses: all, active, expired, revoked\").build();\n    }\n    throw e;\n}","preventionTips":["Use a dropdown with hardcoded status options (all/active/expired/revoked) in the UI.","Omit the status parameter entirely to default to 'all'."],"tags":["apollo-portal","user-token","validation","bad-request"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}