{"record":{"id":"92edcb3da702a2f9","repo":"SonarSource/sonarqube","slug":"cannot-mint-a-gitlab-access-token-for-project-s","errorCode":null,"errorMessage":"Cannot mint a GitLab access token for project '%s': invalid GitLab configuration: %s","messagePattern":"Cannot mint a GitLab access token for project '(.+?)': invalid GitLab configuration: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-common/src/main/java/org/sonar/server/common/almsettings/gitlab/GitlabScmAccessTokenProvider.java","lineNumber":163,"sourceCode":"  }\n\n  private Optional<ScmAccessToken> getCachedToken(TokenCacheKey cacheKey) {\n    ScmAccessToken token = tokenCache.getIfPresent(cacheKey);\n    if (token == null) {\n      return Optional.empty();\n    }\n    if (isExpiring(token)) {\n      tokenCache.invalidate(cacheKey);\n      return Optional.empty();\n    }\n    return Optional.of(token);\n  }\n\n  private ScmAccessToken createToken(TokenMintRequest request) {\n    try {\n      gitlabGlobalSettingsValidator.validate(request.almSetting);\n    } catch (IllegalArgumentException e) {\n      throw new IllegalArgumentException(format(\"Cannot mint a GitLab access token for project '%s': invalid GitLab configuration: %s\",\n        request.safeProjectKey, e.getMessage()), e);\n    }\n    String gitlabUrl = requireNonNull(request.almSetting.getUrl(), \"GitLab url cannot be null\");\n    String personalAccessToken = requireNonNull(request.almSetting.getDecryptedPersonalAccessToken(encryption), \"GitLab personal access token cannot be null\");\n    LocalDate expiresAt = LocalDate.now(ZoneOffset.UTC).plusDays(TOKEN_LIFETIME_DAYS);\n    GitlabProjectAccessToken token = gitlabApplicationClient.createProjectAccessToken(gitlabUrl, personalAccessToken,\n      request.cacheKey.gitlabProjectId, REMEDIATION_AGENT_NAME, TOKEN_MINTING_SCOPES, expiresAt);\n    return new ScmAccessToken(ALM.GITLAB.getId(), REMEDIATION_AGENT_NAME,\n      requireNonNull(token.getToken(), PROJECT_ACCESS_TOKEN_NULL_MESSAGE), formatExpiresAt(token.getExpiresAt(), expiresAt));\n  }\n\n  private static boolean isExpiring(ScmAccessToken token) {\n    try {\n      return token.expiresAt() == null || !LocalDate.parse(token.expiresAt()).isAfter(LocalDate.now(ZoneOffset.UTC).plusDays(TOKEN_ROTATION_MARGIN_DAYS));\n    } catch (DateTimeParseException e) {\n      return true;\n    }\n  }","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-common/src/main/java/org/sonar/server/common/almsettings/gitlab/GitlabScmAccessTokenProvider.java#L145-L181","documentation":"Thrown by GitlabScmAccessTokenProvider.createToken when gitlabGlobalSettingsValidator rejects the ALM setting before minting a GitLab project access token. It signals the stored GitLab DevOps configuration (URL / PAT) is invalid, so short-lived SCM access tokens cannot be provisioned for the project. The original IllegalArgumentException cause is chained.","triggerScenarios":"Automatic token minting (e.g. on PR decoration or code analysis) with an ALM setting whose url is null, PAT is null/undecryptable (e.g. encryption key changed), or fails validate() — typically missing or malformed GitLab global configuration.","commonSituations":"SonarQube encryption secret changed so the stored PAT cannot be decrypted; GitLab ALM setting was created without a PAT; GitLab URL field left blank; PAT deleted on GitLab side causing validation failure.","solutions":["Open Administration > DevOps Platform Integrations, edit the GitLab setting and re-enter a valid URL and PAT with api scope","Re-set the encryption key or re-save secrets after moving/restoring sonar.secretKeyPath so decryption succeeds","Check server logs for the chained IllegalArgumentException message from validate() to see the exact invalid field","Re-save the ALM setting via the web API api/alm_settings/update to refresh decrypted credentials"],"exampleFix":"// before (config)\nalmSetting.url = null; pat = <encrypted, key lost>\n// after\nPOST api/alm_settings/update with url=https://gitlab.example.com and personalAccessToken=<new PAT with api scope>","handlingStrategy":"validation","validationCode":"// validate before minting\nif (almSetting.getUrl() == null || almSetting.getUrl().isBlank()) throw new IllegalArgumentException(\"GitLab url missing\");\ntry { almSetting.getDecryptedPersonalAccessToken(encryption); } catch (Exception e) { throw new IllegalArgumentException(\"PAT undecryptable/missing\", e); }\ngitlabGlobalSettingsValidator.validate(almSetting);","typeGuard":"boolean isMintable(AlmSettingDto s, Encryption encryption) {\n  return s != null && s.getUrl() != null && !s.getUrl().isBlank()\n    && s.getDecryptedPersonalAccessToken(encryption) != null;\n}","tryCatchPattern":"try {\n  ScmAccessToken t = provider.token(projectKey);\n} catch (IllegalArgumentException e) {\n  // invalid GitLab configuration — surface to admin, do not retry blindly\n  log.error(\"Token minting failed: {}\", e.getMessage());\n  throw e;\n}","preventionTips":["Re-save ALM secrets after changing sonar.secretKeyPath","Give PATs api scope and monitor expiry","Validate the GitLab setting via api/alm_settings after edits","Alert on token minting failures — they block PR decoration/analysis"],"tags":["gitlab","token","configuration","integration"],"backgroundTag":"invalid-config-value","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}