vlucas/phpdotenv · error · InvalidEncodingException

Illegal character encoding [%s] specified.

Error message

Illegal character encoding [%s] specified.

What it means

Str::utf8() (src/Util/Str.php:38) validates the requested file encoding with a strict in_array($encoding, mb_list_encodings(), true) before converting file content to UTF-8; on mismatch Reader::readFromFile() rethrows the Result error as Dotenv\Exception\InvalidEncodingException (src/Store/File/Reader.php:77). Because the comparison is strict, the encoding string must match an mbstring name exactly (case and hyphens included). The check only runs when at least one env file was actually read — an unread file fails differently (InvalidPathException).

Source

Thrown at src/Store/File/Reader.php:77

    /**
     * Read the given file.
     *
     * @param string      $path
     * @param string|null $encoding
     *
     * @throws \Dotenv\Exception\InvalidEncodingException
     *
     * @return \PhpOption\Option<string>
     */
    private static function readFromFile(string $path, ?string $encoding = null)
    {
        /** @var Option<string> */
        $content = Option::fromValue(@\file_get_contents($path), false);

        return $content->flatMap(static function (string $content) use ($encoding) {
            return Str::utf8($content, $encoding)->mapError(static function (string $error) {
                throw new InvalidEncodingException($error);
            })->success();
        });
    }
}

View on GitHub (pinned to 416df70283)

Solutions

  1. Use the exact name from mb_list_encodings(): 'UTF-8', 'UTF-16', 'UTF-16BE', 'ISO-8859-1', etc.
  2. Or omit the encoding (pass null) to let mbstring auto-detect — most UTF-8 files need no argument.
  3. Validate configurable encodings before use: in_array($encoding, mb_list_encodings(), true).
  4. Confirm the mbstring extension is installed and current — the valid list comes from it.

Example fix

// before
$dotenv = Dotenv::createImmutable(__DIR__, null, true, 'utf8'); // throws InvalidEncodingException

// after
$dotenv = Dotenv::createImmutable(__DIR__, null, true, 'UTF-8'); // exact mbstring name; or omit for auto-detect
Defensive patterns

Strategy: validation

Validate before calling

// Validate a configurable encoding before handing it to Dotenv::create*():
$encoding = $config['env_encoding'] ?? null; // e.g. 'utf8' from user config
if ($encoding !== null && !in_array($encoding, mb_list_encodings(), true)) {
    throw new InvalidArgumentException(sprintf(
        'env_encoding [%s] is not a valid mbstring encoding; valid examples: %s',
        $encoding,
        implode(', ', array_slice(mb_list_encodings(), 0, 5))
    ));
}

Type guard

function isValidMbEncoding(?string $encoding): bool
{
    return $encoding === null || in_array($encoding, mb_list_encodings(), true); // strict: case-sensitive
}

Try / catch

use Dotenv\Exception\InvalidEncodingException;

try {
    Dotenv::createImmutable($dir, null, true, $encoding)->load();
} catch (InvalidEncodingException $e) {
    // message: 'Illegal character encoding [X] specified.' -> fix the encoding name, do not retry
    log_and_abort($e->getMessage());
}

Prevention

When it happens

Trigger: Passing a fifth argument / fileEncoding that is not an exact mbstring encoding name to Dotenv::create(), createMutable(), createImmutable(), createUnsafeMutable(), createUnsafeImmutable() or createArrayBacked(): 'utf8' or 'UTF8' (mbstring wants 'UTF-8'), lowercase 'utf-8' vs 'UTF-8' (strict compare is case-sensitive), 'latin1' (wants 'ISO-8859-1'), 'ANSI', or a value with trailing whitespace like 'UTF-16 '.

Common situations: Loading UTF-16 .env files exported from Windows tooling; encoding names taken from user config or an HTTP-accepted value; copy-pasting an encoding from a Java/Python project ('utf8'); case differences introduced by mb_strtolower'd config normalization.

Related errors


AI-assisted analysis of vlucas/phpdotenv@416df70283 (2026-08-21). Data as JSON: /api/errors/a4198521257e1716. Report an issue: GitHub.