composer/composer · error · InvalidArgumentException

The package name %s is invalid, it should be lowercase and h

Error message

The package name %s is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+

What it means

When `composer init` is run non-interactively with `--name`, InitCommand::execute validates the value against the strict package-name regex `^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$`. It requires lowercase alphanumerics, exactly one slash separating vendor and package, and no leading/trailing separators. Anything else throws InvalidArgumentException immediately.

Source

Thrown at src/Composer/Command/InitCommand.php:90

Read more at https://getcomposer.org/doc/03-cli.md#init
EOT
            )
        ;
    }

    /**
     * @throws \Seld\JsonLint\ParsingException
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = $this->getIO();

        $allowlist = ['name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload'];
        $options = array_filter(array_intersect_key($input->getOptions(), array_flip($allowlist)), static function ($val) { return $val !== null && $val !== []; });

        if (isset($options['name']) && !Preg::isMatch('{^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $options['name'])) {
            throw new \InvalidArgumentException(
                'The package name '.$options['name'].' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+'
            );
        }

        if (isset($options['author'])) {
            $options['authors'] = $this->formatAuthors($options['author']);
            unset($options['author']);
        }

        $repositories = $input->getOption('repository');
        if (count($repositories) > 0) {
            $config = Factory::createConfig($io);
            foreach ($repositories as $repo) {
                $options['repositories'][] = RepositoryFactory::configFromString($io, $config, $repo, true);
            }
        }

        if (isset($options['stability'])) {

View on GitHub (pinned to c435d285c9)

Solutions

  1. Lowercase the entire name and split it as vendor/package: e.g. `mycompany/my-package`.
  2. Replace invalid characters (- and _ are allowed; spaces/backslashes are not).
  3. If you only have a name, add a vendor prefix from your github.user/USERNAME or COMPOSER_DEFAULT_VENDOR.

Example fix

// before
composer init --name="MyCompany/MyPackage"
// after
composer init --name="mycompany/my-package"
Defensive patterns

Strategy: validation

Validate before calling

$name = $input->getOption('name');
if ($name !== null && !preg_match('{^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $name)) {
    throw new \InvalidArgumentException('Refusing to run init: bad package name');
}

Type guard

function isValidPackageName(string $name): bool {
    return (bool) preg_match('{^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $name);
}

Prevention

When it happens

Trigger: Calling `composer init --name=<value>` in a non-TTY context where <value> has uppercase letters, spaces, backslashes, multiple slashes, a missing vendor part, or starts/ends with a separator — e.g. `--name=MyApp/Foo`, `--name=myapp`, `--name=foo//bar`.

Common situations: Copying a PHP namespace (with backslashes or capitals) as the package name; forgetting the vendor prefix; pasting a name from a URL.

Related errors


AI-assisted analysis of composer/composer@c435d285c9 (2026-08-07). Data as JSON: /api/errors/4655020c0b6ecc23. Report an issue: GitHub.