Blazor WebAssembly を .NET 8 から .NET 9 にアップグレードした直後、ブラウザで MONO_WASM: instantiate_wasm_module() failed や Cannot read properties of undefined (reading 'promise') が出て起動できない――多くは NuGet のバージョン混在が原因です。最短で直す手順と、沼りやすいポイントの潰し方をまとめます。
起きている症状:.NET 9 へ上げたのに、WASM が初期化できず起動しない
Blazor WebAssembly(以下 Blazor WASM)を .NET 8 から .NET 9 に上げたあと、ビルド自体は通るのに、ブラウザで実行すると初期化に失敗して画面が真っ白のまま…というケースがあります。コンソールには、たとえば次のようなメッセージが並びます。
| よく見るログ | 読み取れること | まず疑うべきポイント |
|---|---|---|
MONO_WASM: instantiate_wasm_module() failed | WASM モジュールの読み込み・生成(instantiate)に失敗 | WASM/JS/設定ファイルの不整合、配信されたファイルが壊れている・古い |
TypeError: Cannot read properties of undefined (reading 'promise') | JavaScript 側のランタイム初期化で、想定しているオブジェクトが存在しない | Blazor の JS ランタイムと .NET ランタイム(WASM)が噛み合っていない |
dotnet.runtime.*.js 付近のスタックトレース | Blazor の起動用 JS(_framework 配下)で例外 | /_framework/ に古いファイルが残っている、または生成物が混在 |
https://localhost:xxxx/_framework/... | 開発サーバーが配信している Blazor の成果物が対象 | DevServer / WebAssembly パッケージの更新漏れ、ブラウザキャッシュ |
ポイントは、「ビルドは成功しているのに、実行時(ブラウザ上)で落ちている」ことです。つまり C# のコンパイルエラーではなく、配信された Blazor のランタイム資産(JS/WASM/設定類)の整合性が崩れています。
結論:<TargetFramework>net9.0</TargetFramework> だけ変えても直らない
.NET のアップグレードというと、つい TargetFramework を net8.0 → net9.0 に変えて終わり…と考えがちです。しかし Blazor WASM は、実行に必要なランタイムや起動スクリプトが NuGet パッケージ経由でも供給されます。
そのため、次のような状態になると、見た目は「.NET 9 でビルド」なのに、実態は「.NET 8 と .NET 9 の資産が混ざった状態」になり、起動時に壊れます。
| 混在パターン | 何が起きるか | 典型的な結果 |
|---|---|---|
TargetFramework は net9.0 だが、Blazor WASM パッケージが 8.x のまま | _framework 配下に出力される JS や設定が想定とズレる | dotnet.runtime.*.js で TypeError、WASM 初期化失敗 |
DevServer だけ古い/新しい | 配信(開発サーバー)と生成物の組み合わせが崩れる | ローカルだけ起動しない、更新しても症状が残る |
| 認証系や補助パッケージ(Authentication 等)が 8.x のまま | トランジティブ参照で 8.x が引きずられ、成果物が混ざる | 一見関係なさそうな差分で起動が壊れる |
今回のエラー(Cannot read properties of undefined (reading 'promise'))は、まさに「JavaScript が期待する初期化オブジェクトが存在しない」=JS と WASM の世代がズレているときに起きやすい症状です。
最優先の解決策:Blazor WASM 関連の NuGet を .NET 9 系に揃える
原因がパッケージの混在である以上、最短で効く対処はシンプルです。
- Blazor WebAssembly 本体と DevServer を 9.0.x に更新する
- 可能なら、Blazor/ASP.NET Core 系(Microsoft.AspNetCore.*)も含めて 9.0.x に統一する
- 更新後に bin/obj の削除と ブラウザキャッシュのクリアを行い、古い成果物を一掃する
最低限、次の 2 つは揃えてください(特に DevServer の更新漏れが多いです)。
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0" PrivateAssets="all" />
</ItemGroup>
実運用では 9.0.0 固定より、同一系列の最新パッチ(例:9.0.x)へ揃える方がトラブルが減ります。重要なのは「同じメジャー/マイナー(9.0.*)で揃える」ことです。
Visual Studio での更新手順(NuGet パッケージ マネージャー)
- ソリューションを右クリック → 「NuGet パッケージの管理」
- 「更新プログラム」 タブを開く
- 検索欄に
Microsoft.AspNetCore.ComponentsやWebAssemblyを入れて絞り込む - Blazor/WASM 関連を 9.0.x に更新(可能なら一括更新)
- 更新後にソリューションをクリーン → リビルド
ここでのコツは、「Blazor っぽいものだけ更新」ではなく、Microsoft.AspNetCore.* が混ざっていないか目視で確認しながら揃えることです。
混在を確実に潰す:残りやすいパッケージとチェック観点
.NET 8 の残骸が紛れ込みやすいのは、次のようなパッケージです。プロジェクト構成によっては直接参照していなくても、トランジティブ参照で入ってきます。
| カテゴリ | 例 | 混在すると起きやすいこと |
|---|---|---|
| Blazor WASM 本体 | Microsoft.AspNetCore.Components.WebAssembly | 起動スクリプト・設定の世代ズレ |
| 開発サーバー | Microsoft.AspNetCore.Components.WebAssembly.DevServer | ローカルだけ起動しない、リロードすると壊れる |
| 認証 | Microsoft.AspNetCore.Components.WebAssembly.Authentication | 初期化途中で例外、あるいは _framework の混在 |
| 追加機能/拡張 | Microsoft.AspNetCore.Components.* / Microsoft.Extensions.* | 依存関係が引きずられて混在が再発 |
.csproj でまず見る場所
次の 2 点をセットでチェックします。
<TargetFramework>net9.0</TargetFramework>になっているか<PackageReference>の Blazor/ASP.NET Core 系が 9.0.* に統一されているか
特に、1 つだけ 8.x が残っている状態が危険です。「これだけは古くても動くはず」と思って残すと、起動時に壊れる原因になります。
CLI で混在を洗い出す(トランジティブ参照まで確認)
Visual Studio の UI だけだと、間接的に入っている古いパッケージを見落とすことがあります。次のコマンドが有効です。
# 直接参照 + トランジティブ参照を一覧表示
dotnet list package --include-transitive
# 更新候補を表示(古いパッケージが残っていないか確認)
dotnet list package --outdated
一覧に Microsoft.AspNetCore.Components.WebAssembly や Microsoft.AspNetCore.* が並ぶので、8.x と 9.x が混在していないかをチェックします。混在していたら、基本方針は「9.0.* に上げて揃える」です。
更新後に必ずやる:bin/obj の削除とキャッシュのクリア
パッケージを揃えても、古い生成物やキャッシュが残っていると症状が続くことがあります。特に Blazor WASM は /_framework/ 配下に多数のファイルを出力し、ブラウザ側も積極的にキャッシュするため、「更新したのに直らない」状態に見えやすいです。
ローカル生成物の削除(定番)
- プロジェクトの
binとobjを削除 - 復元(restore)→ 再ビルド
CLI で行うなら次の流れが確実です。
dotnet clean
dotnet restore
dotnet build
「とにかく一度まっさらにしたい」なら、ディレクトリ削除が強力です。
# Windows PowerShell の例(必要に応じてパスは調整)
Remove-Item -Recurse -Force .\bin, .\obj
dotnet restore
dotnet build
NuGet キャッシュのクリア(環境依存の詰まりを解消)
環境によっては、古いパッケージ資産がキャッシュされていて、更新が反映されにくいこともあります。次を実行して、NuGet のローカルキャッシュをクリアします。
dotnet nuget locals all --clear
dotnet restore
頻繁にアップグレード作業をする開発環境ほど、この一手でハマりが減ります。
ブラウザキャッシュが原因で「直ったはずなのに直らない」ケース
Blazor WASM のエラーで厄介なのが、ブラウザが古い /_framework/ を保持してしまうことです。特に以下の条件に当てはまる場合、キャッシュ問題の可能性が跳ね上がります。
- 開発中に何度も
TargetFrameworkを切り替えた - ブラウザのハードリロードをしていない
- PWA(Service Worker)を有効にしているテンプレートを使っている
- 過去に同じポート(例:
https://localhost:7123)で別バージョンを動かしていた
まずは Network で「本当に最新が配信されているか」を見る
DevTools(F12)→ Network を開き、次を確認します。
/_framework/dotnet.runtime.*.jsが 200 で取得できているか(404 や 500 になっていないか)/_framework/dotnet.wasm(または圧縮版)が取得できているか- Disable cache(キャッシュ無効)をオンにしてリロードすると挙動が変わるか
ここで 404 が出るならバージョン混在以前に「ファイルが無い・パスが違う」問題です。200 なのに落ちるなら、古いファイルを掴んでいるか、内容が世代ズレしている可能性が高いです。
Chrome / Edge でのキャッシュクリア手順(手戻りが少ない)
| 状況 | やること | 期待する効果 |
|---|---|---|
| 普通のキャッシュが怪しい | ハードリロード(Ctrl+F5 / Shift+更新) | 静的ファイルを再取得し、古い JS/WASM を排除 |
| 何度やっても直らない | DevTools → Application → Storage → Clear site data | サイト単位でキャッシュ/ストレージを一掃 |
| PWA / Service Worker を使っている | DevTools → Application → Service Workers → Unregister | オフライン資産の配信を止めて最新を取得 |
Service Worker が有効だと、見た目は更新したのに、裏で古い _framework を配り続けることがあります。特にアップグレード直後は、ここが最後の詰まりポイントになりがちです。
「パッケージは揃えたのに still fail」なときの追加チェック
多くのケースは NuGet 混在とキャッシュで解決しますが、それでも instantiate_wasm_module() failed が消えない場合、次の観点で切り分けると効率が良いです。
配信されている .wasm が壊れていないか(Network でサイズとステータスを見る)
dotnet.wasm(または.br,.gz)が 200 で取得できているか- サイズが極端に小さくないか(途中で途切れた配信やエラーページ混入の可能性)
- レスポンスの Content-Type が極端に不自然ではないか
ASP.NET Core のホスティング(開発/本番)であれば通常は問題になりにくいですが、静的ホスティングやリバースプロキシを挟む構成では、圧縮や MIME の設定が絡むことがあります。
「実は JS が古い」パターン(複数プロジェクト/Hosted 構成で起きやすい)
Blazor WASM の Hosted 構成(Client / Server / Shared がある構成)の場合、更新漏れが起きやすい場所があります。
- Client プロジェクト:WASM パッケージが揃っているか(ここが最重要)
- Server プロジェクト:静的ファイル配信・ミドルウェアは正常か(HTTPS、圧縮、キャッシュ関連)
- Shared:依存関係を引きずって 8.x が入っていないか
「Server 側だけ更新した」「Shared だけ更新した」など、部分更新が起きると混在が再発します。アップグレード時は、ソリューション全体を俯瞰して 9.0.* に統一するのが安全です。
Workload 由来の不整合(開発環境の更新不足)
まれに、SDK は .NET 9 なのに、WASM 関連の workload が古くてビルド成果物が想定とズレることがあります。疑わしいときは次を実行して整えます。
dotnet workload update
dotnet workload repair
「ビルドは通るが実行時の資産が変」というときの保険として覚えておくと便利です。
再発防止:アップグレード時にやるべき手順をテンプレ化する
Blazor WASM のアップグレードで一番多い失敗は「どこか 1 箇所だけ取り残して混在する」ことです。次の手順を、作業チェックリストとして固定すると再発が減ります。
| 手順 | やること | 狙い |
|---|---|---|
| SDK/IDE を更新 | .NET 9 SDK と Visual Studio を .NET 9 対応版へ | ビルド/生成物の土台を揃える |
| TargetFramework 更新 | net8.0 → net9.0 | プロジェクトのターゲットを明確化 |
| NuGet を統一 | Blazor/ASP.NET Core 系を 9.0.* に揃える | 実行時資産の世代ズレを防ぐ |
| トランジティブも確認 | dotnet list package --include-transitive | 隠れた 8.x を発見 |
| 生成物を掃除 | bin/obj 削除 → restore → build | 古い成果物の混入を防ぐ |
| ブラウザ側を掃除 | ハードリロード、必要なら Clear site data | 古い _framework の残留を排除 |
チーム開発なら、Directory.Packages.props(中央管理)などでバージョンを固定・統一する運用も有効です。少なくとも「Blazor WASM 関連パッケージは同一系列で揃える」ルールを決めておくと、今回のような実行時エラーを未然に防げます。
よくある質問(つまずきポイントの先回り)
TargetFramework を net9.0 にしたのに、なぜ実行時にだけ落ちるの?
Blazor WASM は、ブラウザ側で動くランタイム(JS/WASM/設定)を /_framework/ に配置して起動します。ここに配置される内容は、参照している NuGet とビルド出力の組み合わせで決まります。TargetFramework だけ更新して NuGet が 8.x のままだと、ブラウザに配信される資産が 8 と 9 で混ざり、JS が期待する初期化情報が存在せず落ちる、という流れになりがちです。
Microsoft.AspNetCore.Components.WebAssembly と DevServer 以外も必ず更新すべき?
最短で直すならこの 2 つが最優先ですが、現実には認証や拡張パッケージが 8.x を引っ張って混在を作ることがあります。結果として「更新したはずなのにまだ落ちる」になりやすいので、基本方針は Blazor/ASP.NET Core 系の 9.0.* 統一が安全です。
更新したのに同じエラーが出続ける
まず疑うのはキャッシュです。特に Service Worker を有効にしている場合、古い資産が残りやすく、_framework の更新が見えません。DevTools の Application で Clear site data と Unregister を実施し、Network で 200 取得できていることまで確認すると解決に近づきます。
まとめ:Blazor WASM の .NET 9 移行で MONO_WASM 初期化エラーが出たら「NuGet 統一」と「キャッシュ削除」
MONO_WASM: instantiate_wasm_module() failed や Cannot read properties of undefined (reading 'promise') は、Blazor WASM の起動資産(JS/WASM/設定)の世代ズレで発生しやすい代表的な症状です。TargetFramework の変更だけでは不十分なことがあるため、Blazor WASM 関連の NuGet を .NET 9 系に揃え、bin/obj とブラウザキャッシュを確実に一掃するのが最短ルートです。
アップグレードは「揃える」「掃除する」「配信物を確認する」の 3 点セットで考えると、実行時トラブルが一気に減ります。

コメント