{"record":{"id":"59d18a4aad0d6c98","repo":"composer/composer","slug":"invalid-credentials-for-url-aborting","errorCode":null,"errorMessage":"Invalid credentials for '{url}', aborting.","messagePattern":"Invalid credentials for '(.+?)', aborting\\.","errorType":"http","errorClass":"Composer\\Downloader\\TransportException","httpStatus":null,"severity":"error","filePath":"src/Composer/Util/AuthHelper.php","lineNumber":162,"sourceCode":"                        $message .= 'create a GitHub OAuth token to access private repos';\n                    }\n                }\n            }\n\n            if (!$gitHubUtil->authorizeOAuth($origin)\n                && (!$this->io->isInteractive() || !$gitHubUtil->authorizeOAuthInteractively($origin, $message))\n            ) {\n                throw new TransportException('Could not authenticate against '.$origin, 401);\n            }\n        } elseif (in_array($origin, $this->config->get('gitlab-domains'), true)) {\n            $message = \"\\n\".'Could not fetch '.Url::sanitize($url).', enter your ' . $origin . ' credentials ' .($statusCode === 401 ? 'to access private repos' : 'to go over the API rate limit');\n            $gitLabUtil = new GitLab($this->io, $this->config, null);\n\n            $auth = null;\n            if ($this->io->hasAuthentication($origin)) {\n                $auth = $this->io->getAuthentication($origin);\n                if (in_array($auth['password'], ['gitlab-ci-token', 'private-token', 'oauth2'], true)) {\n                    throw new TransportException(\"Invalid credentials for '\" . Url::sanitize($url) . \"', aborting.\", $statusCode);\n                }\n            }\n\n            if (!$gitLabUtil->authorizeOAuth($origin)\n                && (!$this->io->isInteractive() || !$gitLabUtil->authorizeOAuthInteractively(parse_url($url, PHP_URL_SCHEME), $origin, $message))\n            ) {\n                throw new TransportException('Could not authenticate against '.$origin, 401);\n            }\n\n            if ($auth !== null && $this->io->hasAuthentication($origin)) {\n                if ($auth === $this->io->getAuthentication($origin)) {\n                    throw new TransportException(\"Invalid credentials for '\" . Url::sanitize($url) . \"', aborting.\", $statusCode);\n                }\n            }\n        } elseif ($origin === 'bitbucket.org' || $origin === 'api.bitbucket.org') {\n            $askForOAuthToken = true;\n            $origin = 'bitbucket.org';\n            if ($this->io->hasAuthentication($origin)) {","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/composer/composer/blob/c435d285c9120efdca35696769c72ea9fdcc0466/src/Composer/Util/AuthHelper.php#L144-L180","documentation":"Thrown by AuthHelper::promptAuthIfNeeded() as a TransportException for a GitLab origin when the stored authentication's password is one of the known-invalid token types ('gitlab-ci-token', 'private-token', 'oauth2') that GitLab no longer accepts, OR when the auth did not change after a re-prompt (credentials unchanged). It aborts rather than retrying with known-bad credentials.","triggerScenarios":"GitLab origin; io has authentication with password in ['gitlab-ci-token','private-token','oauth2'] → throws at line 162 (code = $statusCode); also thrown at line 174 if after re-prompt the auth object is identical to the previous one.","commonSituations":"Using a gitlab-ci-token outside its own project; an expired 'private-token'; an 'oauth2'-style token that the GitLab instance rejects; CI job token cross-project where not allowed.","solutions":["Generate a GitLab personal access token (read_api/read_repository scope) and configure it: composer config gitlab-token.<domain> <token>.","If using CI job tokens, ensure the job token is only used against its own project or configure CI cross-project tokens per GitLab docs.","Remove the stale auth (composer config --unset gitlab-token.<domain>) and re-enter credentials.","Verify the token is not expired and has sufficient scope/role for the project."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Detect known-bad GitLab token types before using them\n$auth = $io->getAuthentication($origin);\nif (in_array($auth['password'] ?? null, ['gitlab-ci-token','private-token','oauth2'], true)) {\n    throw new \\RuntimeException('GitLab password type known to be rejected; use a personal access token.');\n}","typeGuard":"function gitLabTokenIsAcceptable(string $password): bool {\n    return !in_array($password, ['gitlab-ci-token','private-token','oauth2'], true);\n}","tryCatchPattern":"try {\n    $repo->whatProvides($pool, $name);\n} catch (\\Composer\\Downloader\\TransportException $e) {\n    if (str_contains($e->getMessage(), \"Invalid credentials\")) {\n        // unset stale auth and configure a fresh personal access token\n    }\n}","preventionTips":["Use a GitLab personal access token (read_api/read_repository) instead of gitlab-ci-token/private-token/oauth2.","Use CI job tokens only within their own project.","Remove and re-enter auth when tokens expire."],"tags":["gitlab","authentication","token","invalid-credentials","ci"],"backgroundTag":null,"analyzedSha":"c435d285c9120efdca35696769c72ea9fdcc0466","analyzedAt":"2026-08-07T18:58:23.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}