SonarSource/sonarqube · error · IllegalStateException

GitLab repository id is not numeric: '%s'

Error message

GitLab repository id is not numeric: '%s'

What it means

IllegalStateException from ProjectBindingsServiceServerImpl.resolveGitLab: the almpeRepo parameter for a GitLab binding could not be parsed as a numeric GitLab project ID. GitLab bindings must reference the repository by its numeric ID; non-numeric values (paths, URLs, slugs) are rejected with a sanitized message.

Source

Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/almsettings/ws/ProjectBindingsServiceServerImpl.java:289

    AppInstallationToken accessToken = githubApplicationClient.createAppInstallationToken(githubAppConfiguration, installationId, bareRepositoryName(almRepo))
      .orElseThrow(() -> new IllegalStateException(format("Failed to create a GitHub App installation token for repository '%s'", safeAlmRepo)));
    GithubApplicationClient.Repository repository = githubApplicationClient.getRepository(url, accessToken, almRepo)
      .orElseThrow(() -> new IllegalStateException(format("Repository '%s' not found on GitHub", safeAlmRepo)));
    String repoUrl = requireNonNull(repository.getUrl(), format("GitHub returned no url for repository '%s'", safeAlmRepo));
    return new LiveResolution(repoUrl, Long.toString(repository.getId()));
  }

  private LiveResolution resolveGitlab(AlmSettingDto almSetting, ProjectAlmSettingDto projectAlmSetting) {
    String pat = requireNonNull(almSetting.getDecryptedPersonalAccessToken(encryption), PAT_CANNOT_BE_NULL);
    String url = requireNonNull(almSetting.getUrl(), URL_CANNOT_BE_NULL);
    String almRepo = requireNonNull(projectAlmSetting.getAlmRepo(), ALM_REPO_CANNOT_BE_NULL);
    long gitlabProjectId;
    try {
      gitlabProjectId = Long.parseLong(almRepo);
    } catch (NumberFormatException e) {
      // Long.parseLong's own exception message embeds the raw, unsanitized input — rethrow with the same
      // sanitized-message convention used everywhere else in this class before it reaches the resolveLive log.
      throw new IllegalStateException(format("GitLab repository id is not numeric: '%s'", sanitizeForLog(almRepo)));
    }
    Project project = gitlabApplicationClient.getProject(url, pat, gitlabProjectId);
    String repoUrl = requireNonNull(project.getWebUrl(), format("GitLab returned no web URL for project '%s'", sanitizeForLog(almRepo)));
    return new LiveResolution(repoUrl, String.valueOf(project.getId()));
  }

  private LiveResolution resolveAzure(AlmSettingDto almSetting, ProjectAlmSettingDto projectAlmSetting) {
    String pat = requireNonNull(almSetting.getDecryptedPersonalAccessToken(encryption), PAT_CANNOT_BE_NULL);
    String url = requireNonNull(almSetting.getUrl(), URL_CANNOT_BE_NULL);
    String almSlug = requireNonNull(projectAlmSetting.getAlmSlug(), ALM_SLUG_CANNOT_BE_NULL);
    String almRepo = requireNonNull(projectAlmSetting.getAlmRepo(), ALM_REPO_CANNOT_BE_NULL);
    GsonAzureRepo repository = azureDevOpsHttpClient.getRepo(url, pat, almSlug, almRepo);
    String safeAlmRepo = sanitizeForLog(almRepo);
    String repoUrl = requireNonNull(repository.getWebUrl(), format("Azure DevOps returned no web URL for repository '%s'", safeAlmRepo));
    String repoId = requireNonNull(repository.getId(), format("Azure DevOps returned no id for repository '%s'", safeAlmRepo));
    return new LiveResolution(repoUrl, repoId);
  }

View on GitHub (pinned to 184c821202)

Solutions

  1. Convert the GitLab project path to its numeric ID (GitLab UI > project, or GET /api/v4/projects/<url-encoded-path> returns id)
  2. Pass only the numeric id as the repository parameter
  3. Fix the calling integration to store the id returned at binding time

Example fix

// before
resolveGitlab(url, pat, "my-group/my-project")
// after
const {id} = await gitlab.get('/api/v4/projects/my-group%2Fmy-project');
resolveGitlab(url, pat, String(id));
Defensive patterns

Strategy: validation

Validate before calling

function isNumericId(v) { return /^\d+$/.test(String(v).trim()); }
if (!isNumericId(gitlabRepo)) {
  throw new Error(`GitLab repo must be a numeric project id, got: ${gitlabRepo}`);
}

Type guard

const isGitlabProjectId = (v) => typeof v === 'string' && /^\d+$/.test(v);

Try / catch

try {
  await resolver.resolveLive(params);
} catch (e) {
  if (e instanceof IllegalStateException && /not numeric/.test(e.message)) {
    throw new Error('Convert the GitLab path/URL to its numeric project id first');
  }
  throw e;
}

Prevention

When it happens

Trigger: A resolution call (resolveLive) passes almRepo such as 'group/project' or a full URL instead of the numeric GitLab project id.

Common situations: Users paste the project URL or slug into a field expecting the numeric ID; tooling stores web URLs instead of project IDs; API migrations changing identifier conventions.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/cbcee7eb7e942309. Report an issue: GitHub.