{"record":{"id":"ad29f84f3cb05df5","repo":"SonarSource/sonarqube","slug":"the-minimum-value-for-parameter-s-is-s","errorCode":null,"errorMessage":"The minimum value for parameter %s is %s.","messagePattern":"The minimum value for parameter (.+?) is (.+?)\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/usertoken/ws/GenerateActionValidation.java","lineNumber":112,"sourceCode":"    maxTokenLifetime.getDays()\n      .ifPresent(days -> {\n        throw new IllegalArgumentException(\n          String.format(\"Tokens expiring after %s are not allowed. Please use an expiration date.\",\n            LocalDate.now(ZoneOffset.UTC).plusDays(days).format(DateTimeFormatter.ISO_DATE)));\n      });\n  }\n\n  static void compareExpirationDateToMaxAllowedLifetime(LocalDate expirationDate, LocalDate maxExpirationDate) {\n    if (expirationDate.isAfter(maxExpirationDate)) {\n      throw new IllegalArgumentException(\n        String.format(\"Tokens expiring after %s are not allowed. Please use a valid expiration date.\",\n          maxExpirationDate.format(DateTimeFormatter.ISO_DATE)));\n    }\n  }\n\n  static void validateMinExpirationDate(LocalDate localDate) {\n    if (localDate.isBefore(LocalDate.now(ZoneOffset.UTC).plusDays(1))) {\n      throw new IllegalArgumentException(\n        String.format(\"The minimum value for parameter %s is %s.\", PARAM_EXPIRATION_DATE, LocalDate.now(ZoneOffset.UTC).plusDays(1).format(DateTimeFormatter.ISO_DATE)));\n    }\n  }\n\n  static void validateParametersCombination(UserTokenSupport userTokenSupport, DbSession dbSession, Request request, TokenType tokenType) {\n    if (PROJECT_ANALYSIS_TOKEN.equals(tokenType)) {\n      validateProjectAnalysisParameters(userTokenSupport, dbSession, request);\n    } else if (GLOBAL_ANALYSIS_TOKEN.equals(tokenType)) {\n      validateGlobalAnalysisParameters(userTokenSupport, request);\n    }\n  }\n\n  private static void validateProjectAnalysisParameters(UserTokenSupport userTokenSupport, DbSession dbSession, Request request) {\n    checkArgument(userTokenSupport.sameLoginAsConnectedUser(request), \"A Project Analysis Token cannot be generated for another user.\");\n    checkArgument(request.param(PARAM_PROJECT_KEY) != null, \"A projectKey is needed when creating Project Analysis Token\");\n    userTokenSupport.validateProjectScanPermission(dbSession, request.param(PARAM_PROJECT_KEY));\n  }\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/usertoken/ws/GenerateActionValidation.java#L94-L130","documentation":"Thrown by validateMinExpirationDate when creating a user token whose expiration date is not in the future. SonarQube requires token expiration dates to be at least tomorrow (UTC); a same-day or past date is rejected. The message includes the parameter name 'expirationDate' and the minimum acceptable ISO date.","triggerScenarios":"Calling the api/users_tokens/generate (or user_tokens/create) web service with expirationDate set to today's date (UTC) or any past date. The check runs before token creation, comparing the parsed date to LocalDate.now(ZoneOffset.UTC).plusDays(1).","commonSituations":"Scripts automating token generation that compute 'end of today' as the expiry; CI pipelines passing current date due to timezone off-by-one (local timezone ahead/behind UTC); users picking today in the UI-driven API call; reuse of an old token's expiration date.","solutions":["Pass an expirationDate at least one day in the future, computed against UTC.","In automation, generate the date as UTC, e.g. LocalDate.now(ZoneOffset.UTC).plusDays(30), not the local 'today'.","If no long-lived token is needed, omit expirationDate or use the maximum allowed lifespan per the server's token expiration policy."],"exampleFix":"// before\nString expiration = LocalDate.now().toString(); // rejected: today is < min\n// after\nString expiration = LocalDate.now(ZoneOffset.UTC).plusDays(30).format(DateTimeFormatter.ISO_DATE);","handlingStrategy":"validation","validationCode":"LocalDate min = LocalDate.now(ZoneOffset.UTC).plusDays(1);\nif (expirationDate == null || expirationDate.isBefore(min)) {\n  throw new IllegalArgumentException(\"expirationDate must be at least \" + min.format(DateTimeFormatter.ISO_DATE));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always compute expiration dates against UTC, not the local timezone.","Add a minimum-expiry assertion in token-provisioning scripts.","Prefer generous expirations (e.g. +30d) to avoid off-by-one failures at day boundaries."],"tags":["user-token","expiration-date","validation","web-api"],"backgroundTag":"value-out-of-range","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}