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
- Use the exact name from mb_list_encodings(): 'UTF-8', 'UTF-16', 'UTF-16BE', 'ISO-8859-1', etc.
- Or omit the encoding (pass null) to let mbstring auto-detect — most UTF-8 files need no argument.
- Validate configurable encodings before use: in_array($encoding, mb_list_encodings(), true).
- 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
- Prefer omitting fileEncoding (null) — mbstring auto-detects plain UTF-8 files.
- Treat encoding names as an enum from mb_list_encodings(), never free-form config.
- Remember the check is case-sensitive: 'UTF-8' passes, 'utf-8' does not.
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
- Conversion from encoding [%s] failed.
- Failed to parse dotenv file. %s
- At least one environment file path must be provided.
- Unable to read any of the environment file(s) at [%s].
- Expected name to be a non-empty string.
AI-assisted analysis of vlucas/phpdotenv@416df70283 (2026-08-21).
Data as JSON: /api/errors/a4198521257e1716.
Report an issue: GitHub.