laravel/framework · critical · RuntimeException

Unsupported cipher or incorrect key length. Supported cipher

Error message

Unsupported cipher or incorrect key length. Supported ciphers are: {$ciphers}.

What it means

Encrypter constructor throws RuntimeException when the (key, cipher) pair fails static::supported(). supported() checks that the cipher is one of aes-128-cbc/aes-256-cbc/aes-128-gcm/aes-256-gcm AND that the raw key length matches (16 or 32 bytes). The message lists the valid ciphers. A misconfigured APP_KEY or cipher is the canonical cause.

Source

Thrown at src/Illuminate/Encryption/Encrypter.php:61

        'aes-256-gcm' => ['size' => 32, 'aead' => true],
    ];

    /**
     * Create a new encrypter instance.
     *
     * @param  string  $key
     * @param  string  $cipher
     *
     * @throws \RuntimeException
     */
    public function __construct(#[\SensitiveParameter] $key, $cipher = 'aes-128-cbc')
    {
        $key = (string) $key;

        if (! static::supported($key, $cipher)) {
            $ciphers = implode(', ', array_keys(self::$supportedCiphers));

            throw new RuntimeException("Unsupported cipher or incorrect key length. Supported ciphers are: {$ciphers}.");
        }

        $this->key = $key;
        $this->cipher = $cipher;
    }

    /**
     * Determine if the given key and cipher combination is valid.
     *
     * @param  string  $key
     * @param  string  $cipher
     * @return bool
     */
    public static function supported(#[\SensitiveParameter] $key, $cipher)
    {
        if (! isset(self::$supportedCiphers[strtolower($cipher)])) {
            return false;
        }

View on GitHub (pinned to bd6b5437e6)

Solutions

  1. Regenerate the key for the chosen cipher: php artisan key:generate (it base64-encodes 32 random bytes, matching aes-256-cbc).
  2. Ensure config('app.cipher') matches the key size: aes-128-* needs a 16-byte key, aes-256-* needs 32 bytes.
  3. If you set a raw key, prefix with 'base64:' and confirm base64_decode yields 16 or 32 bytes.
  4. When calling previousKeys(), pass only keys whose length matches the current cipher.

Example fix

// before — key/cipher mismatch
// .env: APP_KEY=abc123            (too short)
// config/app.php: 'cipher' => 'aes-256-gcm',

// after
// shell:
// $ php artisan key:generate
//   Application key set successfully.
// .env: APP_KEY=base64:aaaaBBBB....(== 44 chars base64 => 32 raw bytes)
// config/app.php: 'cipher' => 'aes-256-gcm',
Defensive patterns

Strategy: validation

Validate before calling

use Illuminate\Encryption\Encrypter;

$key = config('app.key');
$cipher = config('app.cipher');
if (! Encrypter::supported($key, $cipher)) {
    throw new \RuntimeException('APP_KEY / cipher mismatch — run php artisan key:generate');
}

Type guard

function appKeyValidForCipher(): bool
{
    return \Illuminate\Encryption\Encrypter::supported(config('app.key'), config('app.cipher'));
}

Prevention

When it happens

Trigger: Instantiating new Encrypter($key, $cipher) or booting the EncryptionServiceProvider when APP_KEY length does not match the configured cipher (e.g. APP_KEY is a 32-char ASCII string but cipher is aes-128-cbc, or APP_KEY is empty/malformed). Note: Laravel's 'base64:' prefix decodes to raw bytes; a plain hex/ascii key without prefix is taken literally.

Common situations: Fresh deploy missing APP_KEY; key generated for one cipher then cipher changed in config/app.php; copying .env between projects; truncated APP_KEY; using a hex string instead of base64-encoded random bytes; setting previous_keys to a wrong-length key.

Related errors


AI-assisted analysis of laravel/framework@bd6b5437e6 (2026-08-06). Data as JSON: /data/errors/04febb9eb3335147.json. Report an issue: GitHub.