{"record":{"id":"dd3bca58b949977a","repo":"apolloconfig/apollo","slug":"user-id-and-app-id-can-t-be-empty-at-the-same-time","errorCode":null,"errorMessage":"user id and app id can't be empty at the same time","messagePattern":"user id and app id can't be empty at the same time","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/FavoriteService.java","lineNumber":78,"sourceCode":"        favoriteRepository.findByUserIdAndAppId(loginUserId, favorite.getAppId());\n    if (checkedFavorite != null) {\n      return checkedFavorite;\n    }\n\n    favorite.setPosition(POSITION_DEFAULT);\n    favorite.setDataChangeCreatedBy(user.getUserId());\n    favorite.setDataChangeLastModifiedBy(user.getUserId());\n\n    return favoriteRepository.save(favorite);\n  }\n\n\n  public List<Favorite> search(String userId, String appId, Pageable page, String loginUserId) {\n    boolean isUserIdEmpty = Strings.isNullOrEmpty(userId);\n    boolean isAppIdEmpty = Strings.isNullOrEmpty(appId);\n\n    if (isAppIdEmpty && isUserIdEmpty) {\n      throw new BadRequestException(\"user id and app id can't be empty at the same time\");\n    }\n\n    if (!isUserIdEmpty) {\n      // user can only search his own favorite app\n      if (!Objects.equals(loginUserId, userId)) {\n        userId = loginUserId;\n      }\n    }\n\n    // search by userId\n    if (isAppIdEmpty) {\n      return favoriteRepository.findByUserIdOrderByPositionAscDataChangeCreatedTimeAsc(userId,\n          page);\n    }\n\n    // search by appId\n    if (isUserIdEmpty) {\n      return favoriteRepository.findByAppIdOrderByPositionAscDataChangeCreatedTimeAsc(appId, page);","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/FavoriteService.java#L60-L96","documentation":"Thrown as a BadRequestException by FavoriteService.search() when both userId and appId parameters are null or empty. The search requires at least one filter criterion to prevent unbounded queries. Strings.isNullOrEmpty is used for both, and if both are blank the exception fires before any repository call.","triggerScenarios":"Calling the favorite search API with neither a userId nor an appId query parameter. For example, GET /favorites with no query parameters, or both parameters set to empty strings.","commonSituations":"Client sends a search request without any filter; UI search form submitted empty; API client misconfigured to not pass required filters; frontend bug not validating input before the API call.","solutions":["Provide at least one of userId or appId as a non-empty query parameter when calling search.","Add client-side validation to require at least one search criterion before making the API call.","If listing all favorites is needed for admin purposes, use a dedicated admin endpoint instead of search."],"exampleFix":"// before\nList<Favorite> results = favoriteService.search(null, null, page, loginUserId);\n// after\nif (Strings.isNullOrEmpty(userId) && Strings.isNullOrEmpty(appId)) {\n  throw new IllegalArgumentException(\"Provide userId or appId to search\");\n}\nList<Favorite> results = favoriteService.search(userId, appId, page, loginUserId);","handlingStrategy":"validation","validationCode":"// Validate at least one filter is provided before searching\nif ((userId == null || userId.trim().isEmpty()) && (appId == null || appId.trim().isEmpty())) {\n  throw new IllegalArgumentException(\"At least one of userId or appId must be provided\");\n}\nfavoriteService.search(userId, appId, page, loginUserId);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add client-side validation requiring at least one search criterion.","Default to searching by the current user's userId if no filter is provided.","Document the API requirement that at least one filter is mandatory."],"tags":["apollo-portal","favorite","bad-request","validation","search"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}