{"record":{"id":"1a18f59c8501c327","repo":"SonarSource/sonarqube","slug":"cannot-mint-a-gitlab-access-token-project-ha","errorCode":null,"errorMessage":"Cannot mint a GitLab access token: project '{}' has no repository configured on its DevOps Platform binding","messagePattern":"Cannot mint a GitLab access token: project '(.+?)' has no repository configured on its DevOps Platform binding","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/sonar-webserver-common/src/main/java/org/sonar/server/common/almsettings/gitlab/GitlabScmAccessTokenProvider.java","lineNumber":186,"sourceCode":"    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  }\n\n  @Nullable\n  private static Long parseGitlabProjectId(@Nullable String almRepo, String safeProjectKey) {\n    if (almRepo == null || almRepo.isBlank()) {\n      LOG.warn(\"Cannot mint a GitLab access token: project '{}' has no repository configured on its DevOps Platform binding\", safeProjectKey);\n      return null;\n    }\n    try {\n      return Long.parseLong(almRepo);\n    } catch (NumberFormatException e) {\n      LOG.warn(\"Cannot mint a GitLab access token: project '{}' has a non-numeric GitLab repository identifier '{}'\", safeProjectKey, sanitizeForLog(almRepo));\n      return null;\n    }\n  }\n\n  private static String formatExpiresAt(@Nullable String responseExpiresAt, LocalDate requestedExpiresAt) {\n    if (responseExpiresAt != null && !responseExpiresAt.isBlank()) {\n      try {\n        return LocalDate.parse(responseExpiresAt.trim()).format(DateTimeFormatter.ISO_LOCAL_DATE);\n      } catch (DateTimeParseException e) {\n        LOG.warn(\"GitLab returned an unparseable token expiry '{}', falling back to the requested date\", sanitizeForLog(responseExpiresAt));\n      }\n    }","sourceCodeStart":168,"sourceCodeEnd":204,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-common/src/main/java/org/sonar/server/common/almsettings/gitlab/GitlabScmAccessTokenProvider.java#L168-L204","documentation":"parseGitlabProjectId() converts the project's almRepo (repository slug/identifier stored on the ALM binding) into a numeric GitLab project ID. If almRepo is null or blank, it logs this warning and returns null, which aborts minting since GitLab requires a numeric project id.","triggerScenarios":"Minting a token for a project whose DevOps platform binding exists but has no repository configured (alm_repo column empty) — e.g. binding created without specifying the GitLab repository.","commonSituations":"Admin set up the ALM binding via API without the repository parameter; binding created by import before repo metadata was available; manual project binding where the repo field was left blank in the UI.","solutions":["Set the repository on the binding (Project Settings > DevOps Platform Integration > repository, or api/alm_settings/set_gitlab with the GitLab project numeric id).","Re-run binding import so almRepo is populated from GitLab.","Delete and recreate the binding with the correct GitLab repository identifier.","Skip minting for unbound-repo projects and log clearly instead of failing the pipeline."],"exampleFix":"// before\nPOST api/alm_settings/set_gitlab {almSetting: 'gl', project: 'my.project'} // no repository\n// after\nPOST api/alm_settings/set_gitlab {almSetting: 'gl', project: 'my.project', gitlabProjectId: '12345'}","handlingStrategy":"validation","validationCode":"// verify binding has a repository before minting\nProjectAlmSettingDto b = dbClient.projectAlmSettingDao().selectByProject(db, project).orElseThrow();\nif (b.getAlmRepo() == null || b.getAlmRepo().isBlank()) {\n  throw new IllegalStateException(\"ALM binding has no GitLab repository id\");\n}","typeGuard":"boolean hasGitlabRepo(ProjectAlmSettingDto binding) {\n  return binding.getAlmRepo() != null && !binding.getAlmRepo().isBlank();\n}","tryCatchPattern":null,"preventionTips":["Always pass the GitLab project id when setting bindings via api/alm_settings/set_gitlab.","Validate the repo field is non-empty in provisioning templates.","Re-run binding import when repo metadata is missing.","Alert on bindings created without a repository."],"tags":["gitlab","alm-binding","missing-configuration","token-minting"],"backgroundTag":"missing-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"}