Windows環境でDocker Composeを使う際、PowerShellで作成した.envファイルが原因でコンテナが起動できないケースがあります。エラーメッセージに\xff\xfeunexpected characterが含まれている場合、ファイルのエンコードが原因です。

エラーの全文

failed to read C:\Users\user\project\.env: line 1: unexpected character "?" in variable name "\xff\xfeG\x00O\x00O\x00G\x00L\x00E\x00_\x00A\x00P\x00I\x00_\x00K\x00E\x00Y\x00=\x00A\x00I\x00z\x00a\x00..."

\xff\xfe はUTF-16 LEのBOM(Byte Order Mark)です。続く\x00が各文字の後ろに並んでいることから、ファイル全体がUTF-16 LEで保存されていることがわかります。Docker ComposeのenvファイルパーサーはUTF-8(BOMなし)のみを受け付けるため、このファイルを読み込もうとした瞬間にクラッシュします。

よくある原因

PowerShellのechoコマンドはUTF-16 LEで書き出す

WindowsのPowerShell(5.1系)では、リダイレクト演算子>echoコマンドがデフォルトでUTF-16 LE(BOM付き)を使用します。

# これをやってはいけない
echo GOOGLE_API_KEY=AIzaSy... > .env
# → .envがUTF-16 LE(BOM付き)で保存される

Linuxや macOSのシェルと違い、PowerShellは歴史的な経緯からUTF-16をデフォルトエンコードとして採用しています。echoSet-Contentを使う限り、意識しない限りこの問題が発生します。

VSCodeのエンコード設定が変わっている場合

VSCodeでファイルを新規作成・保存する際、右下のステータスバーが「UTF-16 LE」になっているとDocker Composeが読めないファイルが生成されます。

診断方法

.envファイルの先頭バイトを確認します。

# 先頭4バイトを16進数で確認
$bytes = [System.IO.File]::ReadAllBytes(".env")
$bytes[0..3] | ForEach-Object { $_.ToString("X2") }

正常(UTF-8 BOMなし):

47 4F 4F 47   ← "GOOG"の文字コード(例:GOOGLE_API_KEY=...)

異常(UTF-16 LE BOM付き):

FF FE 47 00   ← \xff\xfe がBOM、その後\x00が混入

解決手順

方法1:既存の.envファイルをUTF-8に変換する(即時対応)

# UTF-16で書かれた.envをUTF-8(BOMなし)に変換して上書き
$content = Get-Content ".env" -Encoding Unicode -Raw
[System.IO.File]::WriteAllText(
    (Resolve-Path ".env").Path,
    $content.Trim() + "`n",
    [System.Text.UTF8Encoding]::new($false)
)

$falseは「BOMを付けない」を意味します。UTF8Encoding::new($true)にするとBOM付きになるため注意してください。

方法2:最初からUTF-8で.envを作成する(恒久対応)

# Before(NGパターン)
echo GOOGLE_API_KEY=AIzaSy... > .env

# After(OKパターン)
[System.IO.File]::WriteAllText(
    "$PWD\.env",
    "GOOGLE_API_KEY=AIzaSy...`n",
    [System.Text.UTF8Encoding]::new($false)
)

複数の変数を書く場合はヒアストリングを使います。

$envContent = @"
GOOGLE_API_KEY=AIzaSy...
DATABASE_URL=postgresql://...
DEBUG=false
"@
[System.IO.File]::WriteAllText(
    "$PWD\.env",
    $envContent,
    [System.Text.UTF8Encoding]::new($false)
)

方法3:VSCodeで修正する

  1. .envをVSCodeで開く
  2. 右下のステータスバーで現在のエンコードを確認(「UTF-16 LE」と表示されているはず)
  3. クリックして「エンコード付きで保存」→「UTF-8」を選択

Before / After の対比

Before(問題のあるファイル):

バイト列: FF FE 47 00 4F 00 4F 00 47 00 4C 00 45 00 ...
文字列:   (BOM)G  O  O  G  L  E  ...(各文字の後ろに\x00が混入)

Docker Composeの起動結果:

failed to read .env: line 1: unexpected character "?" in variable name "\xff\xfeG\x00O\x00O\x00G\x00..."

After(修正後のファイル):

バイト列: 47 4F 4F 47 4C 45 5F 41 50 49 5F 4B 45 59 ...
文字列:   G  O  O  G  L  E  _  A  P  I  _  K  E  Y  ...(クリーンなASCII)

Docker Composeの起動結果:

[+] Running 2/2
 ✔ Container app-backend   Started
 ✔ Container app-frontend  Started

根本的な対策:.gitattributesで管理する

チーム開発の場合、リポジトリに.gitattributesを追加することでエンコードを強制できます。

# .gitattributes
.env*    text eol=lf
*.md     text eol=lf
*.py     text eol=lf
*.yml    text eol=lf

ただし.envはGit管理対象外(.gitignoreに記載)にするのが一般的なので、あくまで.env.exampleなどのテンプレートファイルに適用するのが現実的です。

それでも解決しない場合

  • WSL2を経由する: WSL2のシェル(bash/zsh)からechoでファイルを作成するとデフォルトがUTF-8になります
  • PowerShell 7以降に移行: PowerShell 7(pwsh)はデフォルトエンコードがUTF-8に変わっています。winget install Microsoft.PowerShellでインストール可能です
  • docker composeではなくdocker-composeを使う: 古いv1系は挙動が違うことがありますが、現在は非推奨のため根本解決にはなりません

免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。