Lesstep
GitLab.com and Self-Managed · access tokens · Checked October 24, 2026

GitLab: 401 "invalid_token" — "Token is expired" or "Token was revoked"

GitLab knows the token but no longer accepts it: it has expired, or it has been revoked. GitLab refuses with HTTP 401 and says which in error_description. An expired token cannot be reactivated; create a new one and put it where the old one was. Unlike a missing scope (403 insufficient_scope), nothing about the token's scopes will fix this.

The whole answer

As GitLab builds it (lib/api/api_guard.rb), for an expired token:

HTTP 401
WWW-Authenticate: Bearer realm="Protected by OAuth 2.0", error="invalid_token",
  error_description="Token is expired. You can either do re-authorization or token refresh."

{"error": "invalid_token",
 "error_description": "Token is expired. You can either do re-authorization or token refresh."}

The same answer from a public report (a package upload in 2026). The error_description is one of three:

A token GitLab does not know at all (mistyped, cut short when pasted, or made on another GitLab server) gets a plainer 401 instead: {"message": "401 Unauthorized"} (lib/api/helpers.rb). To see which answer you have, call the address that failed with curl:

curl -i --header "PRIVATE-TOKEN: your-token" "https://gitlab.com/api/v4/user"

Expired

From GitLab's personal access tokens page:

Revoked

Create a new token

  1. In GitLab: your avatar in the upper-right corner, Edit profile, then Access > Personal access tokens in the left sidebar (the names in GitLab's docs on October 24, 2026; older versions differ). From Generate token, choose Legacy token.
  2. A name, an expiry date (up to 365 days away by default) and the same scopes as before. GitLab can open the form with them filled in, for example https://gitlab.com/-/user_settings/personal_access_tokens?name=IDE&scopes=api (prefilling a token; on a Self-Managed server, use its address).
  3. Copy the token. GitLab shows it only until you leave or refresh the page.
  4. Put it everywhere the old one was.

In IntelliJ IDEA: "Login failed. Check your API token or GitLab version."

When you log in with a token in the GitLab support built into IntelliJ IDEA, it first reads the server's version with that token: the GraphQL metadata query, and if that fails, the REST /version endpoint (GitLab: Metadata API). Both need a token GitLab accepts. In the source (checked October 30, 2026; IntelliJ IDEA: GitLabTokenLoginPanelModel.kt, GitLabSecurityUtil.kt, GitLabServersManager.kt, GitLabApi.kt, GitLabLoginErrorStatusPresenter.kt):

GitLab merge requests and pipelines in IntelliJ IDEA

Lesstep makes two plugins for JetBrains IDEs 2024.1 or later that read GitLab with read_api and change things with api: Merge Request Inbox for GitLab and Pipeline Inbox for GitLab CI. When GitLab refuses the token with 401 while they read, they say that the token expired, was revoked or is from another GitLab instance, show GitLab's own description, and offer to open their settings, which have a link to GitLab's form with the name and scope filled in (GitLab 16.7 or later). The token is kept in the IDE's password safe, so replacing it there is the only change. Reading is free; approving, commenting and merging, or retrying, cancelling and running pipelines, are Pro (US$1.50 a month, with a 30-day trial).

GITLAB is a trademark of GitLab Inc.; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with or endorsed by GitLab Inc. or JetBrains.

More: GitLab "insufficient_scope" · GitLab 404 "Project Not Found" · GitLab merge refused (405, 409, 422) · GitLab approval refused (401, 409) · GitLab comment or thread refused (400, 403) · GitLab merge request not created (409, 422, 400) · GitLab rebase refused or failed (403, 409) · GitLab merge request list refused (400, 404) · GitLab merge request changes cut short ("1000+", too_large) · GitLab 429 "Retry later" (rate limits) · GitLab "compare_timeout": true (diff limits) · GitLab merge request plugins for IntelliJ IDEA, compared · GitLab pipelines in JetBrains IDEs, compared · 日本語