ERR_INVALID_PACKAGE_CONFIG の正体は、3バイトのBOMだった
空に見えるのに空ではない。lsで見えるのはサイズ3という数字だけ

ホームディレクトリで node を動かしたら、身に覚えのないエラーが出ました。
Error: Invalid package config C:\Users\<ユーザー名>\package.json
at Object.getNearestParentPackageJSON (node:internal/modules/package_json_reader)
code: 'ERR_INVALID_PACKAGE_CONFIG'
そこにプロジェクトは置いていません。npm init をした覚えもありません。それでも require() を含むスクリプトが軒並み落ちます。
中身を見たら、3バイトしかなかった
まずファイルの大きさを見ます。
$ ls -la ~/package.json
-rw-r--r-- 1 user 3 Aug 16 02:20 /c/Users/<ユーザー名>/package.json
3バイト。 中身を16進で見ると、正体が分かりました。
$ xxd ~/package.json
00000000: efbb bf ...
EF BB BF は UTF-8 の BOM(Byte Order Mark)です。つまりこのファイルは空ではなく、BOMだけが入っている状態でした。JSONとしては当然パースできません。
ここが分かりにくいところで、cat で開いても何も見えず、エディタでも空に見えます。「空っぽに見えるのに壊れている」ので、中身を疑う発想になりにくいのです。サイズが 0 ではなく 3 であることだけが手がかりでした。
なぜホームディレクトリのファイルが、あちこちを壊すのか
Node.js はモジュールを解決するとき、カレントディレクトリから親をたどって最も近い package.json を探します。プロジェクト直下に無ければ、その上、さらに上、と登っていきます。
つまりホームディレクトリに壊れた package.json が1つあると、その配下で動かすスクリプトすべてが、自分のディレクトリに package.json を持たない限り巻き込まれます。エラーメッセージにはホームのパスが出ているのに、動かしているのは別の場所のスクリプト——という状況になり、原因の場所と症状の場所が一致しません。
どこから来たのか
作成日時を見ると、数日前の深夜でした。心当たりは PowerShell です。Windows PowerShell 5.1 では、リダイレクトや Out-File が既定で BOM付きで書き出します。空文字列を書き込むと、中身が無いのに BOM だけのファイルができます。
# これで「3バイトのファイル」ができる
"" | Out-File package.json
おそらく、何かのコマンドが空の出力をリダイレクトした結果です。作った瞬間はエラーが出ないので、数日後にまったく別の作業で踏むことになります。
なお、PowerShell 5.1 の既定エンコーディングそのものが引き起こす文字化けについては、PowerShell の Set-Content で日本語 UTF-8 ファイルが壊れる話にまとめてあります。今回の3バイトのファイルは、その仕様の副産物です。
直し方
正しい package.json をそこに置く必要はありません。そもそも要らないファイルなので、退避してから消すのが確実です。
$ cp ~/package.json /tmp/package.json.bak # 念のため退避
$ rm ~/package.json
$ node -e "console.log(typeof require('path').join)"
function # 直った
もしそこに本当に package.json が必要なら、BOM無しのUTF-8で書き直します。PowerShell 5.1 なら Set-Content -Encoding utf8 でも BOM が付くので、BOM無しにしたいときは .NET の WriteAllText を使うのが確実です。
同じ形のエラーを見分ける
この件は「JSONが壊れている」という一言でまとめられがちですが、実際には次の3つは別物です。
- サイズ0 — 完全に空。多くのツールは「空だから既定値」と扱ってくれることがある
- BOMだけ(3バイト) — 空に見えるが中身がある。JSONパーサは必ず落ちる
- BOM + 正しいJSON — 見た目は正常。パーサによって通ったり落ちたりする(これがいちばん厄介)
設定ファイルが理由なく壊れているときは、ls でサイズを見て、0でも期待どおりでもない中途半端な数字なら16進で開く。それだけで数十分は節約できます。
持ち帰れる形にすると
ERR_INVALID_PACKAGE_CONFIGは「そのパスの package.json が JSON として読めない」という意味。プロジェクトの外を指していることもある。- Node はカレントから親をたどって package.json を探すので、ホームに壊れた1つがあると配下が全部巻き込まれる。
- 3バイトのファイルは BOM だけを疑う(
EF BB BF)。空に見えて空ではない。 - PowerShell 5.1 の書き出しは既定で BOM 付き。空の出力をリダイレクトすると壊れたファイルが生まれる。
- 要らない設定ファイルなら、直すより退避して消すほうが速くて確実。
よくある質問
ERR_INVALID_PACKAGE_CONFIG はどういう意味のエラー?
エラーメッセージに書かれているパスの package.json が、JSONとして読めないという意味です。構文エラーのほか、中身がBOMだけといったケースも含みます。注意点として、そのパスは作業中のプロジェクトとは限りません。Nodeはカレントディレクトリから親をたどって最も近い package.json を探すため、ホームディレクトリなど上位に壊れたファイルがあると、その配下すべてで同じエラーが出ます。
中身が空に見える package.json が壊れているのはなぜ?
UTF-8のBOM(EF BB BF)だけが入っている可能性が高いです。テキストとしては何も表示されませんが3バイトのデータがあり、JSONパーサは先頭でつまずきます。lsでサイズが0ではなく3になっているのが手がかりで、xxdやhexdumpで開くと確認できます。Windows PowerShell 5.1 は既定でBOM付きで書き出すため、空の出力をリダイレクトすると簡単に生まれます。
ホームディレクトリの package.json は消してよい?
そこにNodeプロジェクトを作った覚えがないなら、消して構いません。念のため別の場所へコピーしてから削除し、node -e で require が通ることを確認してください。もし必要なファイルであれば、BOM無しのUTF-8で書き直します。PowerShell 5.1 では Set-Content -Encoding utf8 でもBOMが付くため、BOM無しが必要なときは .NET の WriteAllText を使うのが確実です。