composer/composer · warning · UnexpectedValueException

Invalid input

Error message

Invalid input

What it means

Thrown by the input validator used while prompting for a public key during --update-keys. The first line pasted must match the PEM header '-----BEGIN PUBLIC KEY-----' exactly (after trim); anything else fails validation. It is an \UnexpectedValueException, and because it is raised inside the askAndValidate() validator the prompt simply re-asks the user rather than aborting the command.

Source

Thrown at src/Composer/Command/SelfUpdateCommand.php:344

        return 0;
    }

    /**
     * @throws \Exception
     */
    protected function fetchKeys(IOInterface $io, Config $config): void
    {
        if (!$io->isInteractive()) {
            throw new \RuntimeException('Public keys can not be fetched in non-interactive mode, please run Composer interactively');
        }

        $io->write('Open <info>https://composer.github.io/pubkeys.html</info> to find the latest keys');

        $validator = static function ($value): string {
            $value = (string) $value;
            if (!Preg::isMatch('{^-----BEGIN PUBLIC KEY-----$}', trim($value))) {
                throw new \UnexpectedValueException('Invalid input');
            }

            return trim($value)."\n";
        };

        $devKey = '';
        while (!Preg::isMatch('{(-----BEGIN PUBLIC KEY-----.+?-----END PUBLIC KEY-----)}s', $devKey, $match)) {
            $devKey = $io->askAndValidate('Enter Dev / Snapshot Public Key (including lines with -----): ', $validator);
            while ($line = $io->ask('', '')) {
                $devKey .= trim($line)."\n";
                if (trim($line) === '-----END PUBLIC KEY-----') {
                    break;
                }
            }
        }
        file_put_contents($keyPath = $config->get('home').'/keys.dev.pub', $match[0]);
        $io->write('Stored key with fingerprint: ' . Keys::fingerprint($keyPath));

View on GitHub (pinned to c435d285c9)

Solutions

  1. Copy the full PEM block from https://composer.github.io/pubkeys.html starting at '-----BEGIN PUBLIC KEY-----' and ending at '-----END PUBLIC KEY-----'.
  2. Paste the BEGIN line verbatim as the first input.
  3. If the validator keeps rejecting, re-copy from the official pubkey page avoiding extra whitespace.

Example fix

// before (first pasted line)
BEGIN PUBLIC KEY
// after
-----BEGIN PUBLIC KEY-----
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate the first line before pasting it into the prompt
$firstLine = trim($input);
if (!preg_match('{^-----BEGIN PUBLIC KEY-----$}', $firstLine)) {
    fwrite(STDERR, "First line must be exactly '-----BEGIN PUBLIC KEY-----'.\n");
}

Type guard

function isPemHeader(string $line): bool\n{\n    return preg_match('{^-----BEGIN PUBLIC KEY-----$}', trim($line)) === 1;\n}

Prevention

When it happens

Trigger: During `composer self-update --update-keys`, pasting a first line that is not exactly '-----BEGIN PUBLIC KEY-----' — missing dashes, extra whitespace, pasting a fingerprint instead, or a wrong-format key block (SelfUpdateCommand.php:341-345).

Common situations: Copying only part of the PEM header; pasting an SSH/PGP key by mistake; trailing spaces from a copy; pasting the key fingerprint rather than the PEM body.

Related errors


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