composer/composer · error · UnexpectedValueException
Invalid url given for Composer repository: {url}
Error message
Invalid url given for Composer repository: {url} What it means
After normalising the url, ComposerRepository parses it with parse_url() and requires a valid scheme. If parse_url returns false or there is no scheme, it throws UnexpectedValueException because it cannot decide how to fetch metadata. The url in the message is sanitised to avoid leaking credentials.
Source
Thrown at src/Composer/Repository/ComposerRepository.php:184
// it is a local path, add file scheme
$repoConfig['url'] = 'file://'.$localFilePath;
} else {
// otherwise, assume http as the default protocol
$repoConfig['url'] = 'http://'.$repoConfig['url'];
}
}
$repoConfig['url'] = rtrim($repoConfig['url'], '/');
if ($repoConfig['url'] === '') {
throw new \InvalidArgumentException('The repository url must not be an empty string');
}
if (str_starts_with($repoConfig['url'], 'https?')) {
$repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
}
$urlBits = parse_url(strtr($repoConfig['url'], '\\', '/'));
if ($urlBits === false || empty($urlBits['scheme'])) {
throw new \UnexpectedValueException('Invalid url given for Composer repository: '.Url::sanitize($repoConfig['url']));
}
if (!isset($repoConfig['options'])) {
$repoConfig['options'] = [];
}
if (isset($repoConfig['allow_ssl_downgrade']) && true === $repoConfig['allow_ssl_downgrade']) {
$this->allowSslDowngrade = true;
}
$this->options = $repoConfig['options'];
$this->url = $repoConfig['url'];
// force url for packagist.org to repo.packagist.org
if (Preg::isMatch('{^(?P<proto>https?)://packagist\.org/?$}i', $this->url, $match)) {
$this->url = $match['proto'].'://repo.packagist.org';
}
$baseUrl = rtrim(Preg::replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');View on GitHub (pinned to 6ffc117740)
Solutions
- Specify a full url with an explicit scheme, e.g. https://repo.example.com.
- For local paths use an absolute filesystem path or a file:// URL.
- Remove stray backslashes or encoded characters from the url.
Example fix
// before
{ "type": "composer", "url": "repo.example.com\\packages.json" }
// after
{ "type": "composer", "url": "https://repo.example.com/packages.json" } Defensive patterns
Strategy: validation
Validate before calling
$url = $config['url'] ?? '';
if (parse_url((string) $url) === false || empty(parse_url((string) $url)['scheme'])) {
throw new \InvalidArgumentException("Repository url has no valid scheme: {$url}");
} Type guard
function hasValidScheme(string $url): bool {
$bits = parse_url(strtr($url, '\\', '/'));
return $bits !== false && !empty($bits['scheme']);
} Prevention
- Always include the scheme (https:// or file://) in repository urls.
- Avoid backslashes in urls; use forward slashes.
- Run `composer validate` to surface malformed repository definitions.
When it happens
Trigger: A repository url that, after scheme-prefixing and slash-trimming, still has no parseable scheme — e.g. a url consisting only of a path fragment, or one containing characters that make parse_url fail. This typically happens when the input lacks a protocol and realpath() also fails (so the http:// default isn't added cleanly).
Common situations: Urls with backslashes or malformed characters; urls that are relative paths which don't resolve on disk; copy-paste of a url missing its protocol in an unusual form; typos like 'htps://'.
Related errors
- The repository url must not be an empty string
- A repository of type "package" contains an invalid package d
- Repository "filter" must be a boolean or an object mapping a
- Repository "filter" keys must be non-empty list-name strings
- Repository "filter" entry for "%s" must be a boolean; got %s
AI-assisted analysis of composer/composer@6ffc117740 (2026-08-07).
Data as JSON: /api/errors/58cdd36d5bc23754.
Report an issue: GitHub.