トラブルシューティング
具体的な修正方法つきの既知の失敗モード — インストール、bundle 設定、import query、module worker、プロジェクトルート外の import、esbuild バイナリのエラー。
このページで扱うこと
直接名前を付けて解説する価値があるほど頻繁に出てくる失敗モードを、症状ベースで索引したものです。それぞれについて、実際に目にするメッセージと修正方法を示します。あなたの問題がここにない場合は、リンク先の概念/ガイドのページが、各機能の土台となる挙動全体を扱っています。
curl | sh インストールがリリースタグを解決できない
症状: curl インストーラ が次のいずれかで終了する。
error: could not resolve the latest release tag from GitHub APIerror: could not resolve the latest prerelease tag from GitHub API (no prerelease found in the last 30 releases)原因: install.sh は何かをダウンロードする前に、GitHub Releases API からタグを解決します。
ZFB_VERSIONが未設定の場合、最新の 非プレリリース リリースを要求します。通常はこれで解決できます。失敗するのは、API に到達できない、レート制限を受けている、あるいはリクエストが何らかの理由でブロックされている場合だけです。Node なしでインストール を参照してください。ZFB_VERSION=latest-prereleaseの場合、直近 30 件のリリースを走査して"prerelease": trueが付いたものを探します。直近 30 件のいずれもプレリリースでない場合(たとえば、その後いくつかの安定版がリリースされ、プレリリースがそのウィンドウから押し出された場合)、同じように解決に失敗します。
対処:
レート制限を受けている場合やプロキシ環境の場合: リリースページ から厳密なタグを固定してください(例:
ZFB_VERSION=v1.0.0)。タグ解決のリクエスト自体をスキップできます。プレリリースを使いたいが
latest-prereleaseの解決に失敗する場合(直近 30 件にプレリリースが 1 件も含まれていない場合): 代わりにプレリリースのタグを直接固定してください(例:ZFB_VERSION=v0.1.0-next.99)。
musl/Alpine is not supported yet
症状:
[zfb] musl/Alpine is not supported yet — no @takazudo/zfb-linux-*-musl package exists.
Use a glibc-based Linux image (e.g. Debian/Ubuntu) instead of Alpine. 原因: zfb は glibc にリンクされたプリビルドのプラットフォームバイナリしか配布しておらず、@takazudo/zfb-linux-*-musl パッケージは存在しません。npm ラッパー(packages/)は musl ランタイム(Alpine の / 動的ローダー、あるいは Node 自身のランタイムレポートに glibc バージョンが存在しないこと)を検出し、glibc バイナリを不透明な動的ローダーエラーでクラッシュさせる代わりに、この親切なメッセージで失敗します。スタンドアロンの curl/PowerShell インストーラはこの方法で musl を検出できず(OS/CPU しかチェックしません)、glibc バイナリをダウンロードしてしまい、それが実行時にそのまま失敗します。
対処: Alpine の代わりに glibc ベースの Linux ベースイメージ(Debian、Ubuntu)を使ってください。Dockerfile でも、CI ランナーでも、任意のコンテナイメージでも同様です。今日、musl 上でネイティブに zfb を動かす回避策はありません。サポートされるプラットフォームのマトリクスは インストール と Node なしでインストール を参照してください。
2.12.0 のインストールで ERR_PNPM_TRUST_DOWNGRADE
症状: pnpm のオプトイン設定 trustPolicy を no-downgrade にしていると、@takazudo/zfb* のいずれかを 2.12.0 でインストール/アップグレードする際に失敗します。
ERR_PNPM_TRUST_DOWNGRADE High-risk trust downgrade for "@takazudo/zfb@2.12.0" (possible package takeover)
Trust checks are based solely on publish date, not semver. A package cannot be
installed if any earlier-published version had stronger trust evidence. Earlier
versions had provenance attestation, but this version has no trust evidence.trustPolicy はオプトイン(デフォルトは off)で、pnpm 10.21 以降で利用できます。既存のロックファイルで回避できるかどうかは、使っているバージョンによって異なります。
| インストール方法 | pnpm 10.21 – 11.1 | pnpm 11.2 以降 |
|---|---|---|
| 新規/強制的な解決 | 失敗 | 失敗 |
pnpm install --frozen-lockfile | 成功 | 失敗 |
pnpm 11.2 で、解決済みロックファイルの各エントリに対して有効なサプライチェーンポリシーを再適用する検証パスが追加されました。そのため、すでに 2.12.0 を固定しているロックファイルをコミットしていても、11.1 では通り、11.2 では失敗します。
原因: 2.12.0 のパッケージには npm の provenance attestation が付いていない一方、2.11.0 には付いています。これはパッケージの乗っ取りではありません。2.12.0 は zfb の published-release recovery パス — すでに公開済みのタグを再ビルドする、main からの workflow_dispatch 実行 — を通じて公開されました。その実行における GitHub OIDC のアイデンティティは、成果物が実際にビルドされた古いタグのコミットではなく main のワークフローコミットを指すため、出所を誤って示す attestation を付けるくらいならと、意図的に attestation なしで公開しています。この経緯は issue #2623 に記録されています。
通常のインストールで取得される 6 つのうち 5 つのパッケージが影響を受けます。@takazudo/zfb-darwin-x64 が検出されなかったのは、2.12.0 まで attestation が付いておらず、pnpm が比較する対象を持たなかったからです。2.13.0 以降は、他のパッケージと同様に attestation が付与されています。
対処: npm のバージョンはイミュータブルなので、2.12.0 自体が後から attestation を得ることはありません。次の順で検討してください。
2.13.0以降に上げる。それらのリリースは通常のタグ/リリースパスを通り provenance が復活するため、ダウングレード判定が解消されます。これが本来の修正です。まだアップグレードできない場合は
2.11.0に留まる。こちらは attestation があり、影響を受ける2.12.0を回避できます。どうしても今
2.12.0が必要な場合は、pnpm-workspace.yamlのtrustPolicyExcludeで該当パッケージだけを除外する。他のすべての依存関係についてはポリシーが有効なままになります。trustPolicy: no-downgrade trustPolicyExclude: - "@takazudo/zfb@2.12.0" - "@takazudo/zfb-darwin-arm64@2.12.0" - "@takazudo/zfb-linux-arm64-gnu@2.12.0" - "@takazudo/zfb-linux-x64-gnu@2.12.0" - "@takazudo/zfb-win32-x64-msvc@2.12.0"各エントリでバージョンを固定しておくと、アップグレード時に除外が自動的に失効します。なお、名前のパターンとバージョンを組み合わせることはできません(
"@takazudo/はzfb*@2. 12. 0" ERR_PNPM_INVALID_TRUST_POLICY_EXCLUDEで拒否されます)。上記のように厳密なname@versionを列挙するか、全バージョンの除外を許容できる場合は"@takazudo/zfb*"のようなバージョンなしの glob を使ってください。
trustPolicy 自体を無効化しても回避できますが、これら 5 つではなくすべての依存関係についてガードが外れます。範囲を限定した除外を優先してください。
import.meta.glob(...) のビルドエラー
症状(zfb build から。または zfb dev からは警告 + リバンドルのスキップ):
zfb islands: `import.meta.glob(...)` cannot be safely shipped from one or more
files reachable from a "use client" island. zfb can currently expand eager
string-literal globs only when the glob call is in an island-reachable module
that is written as a real shadow copy; unsupported forms and globs found only in
raw-mirrored glob target/subtree files would ship to the browser unexpanded and
throw at hydration: <file> — ... Follow the remediation above for each file,
use the eager string-literal form where applicable, replace the glob with
explicit static imports, or move the usage to a server-only (non-"use client")
module. Tracked at https://github.com/Takazudo/zudo-front-builder/issues/1385
and https://github.com/Takazudo/zudo-front-builder/issues/1412. 原因: import.meta.glob は Vite 専用のビルド時マクロです。島をバンドルする esbuild はこれをネイティブには理解しないため、zfb は esbuild がファイルを目にする前に、サポートされる唯一の形式を自分で展開します。サポートされるのは、glob 呼び出しが島から到達可能なモジュール内にあり、そのモジュールが展開済みの実体あるシャドウコピーファイルとして書き出される場合の import.meta.glob("<string-literal>", { eager: true }) だけです。パターンはインポート元ファイル自身のディレクトリ配下に解決される必要があります。それ以外のすべて — デフォルトの lazy 形式、{ eager: false }、リテラルでないパターン、import/query/as オプション、. でディレクトリを抜け出すパターン — は拒否されます。JS 風のファイルが raw-mirrored な glob ターゲット、またはサブツリー内の companion ファイルとしてだけ到達していて、その中に glob がある場合も拒否されます。そうしなければ、そのファイルは未展開のままブラウザへ配信され、hydration 中に例外を投げるためです。
対処: 完全なサポートマトリクスと代替手段は Islands: import.meta.glob のサポート を参照してください。使える場所では eager + 文字列リテラル形式に直し、ネストした glob は島から到達可能なモジュールへ hoist するか、raw-mirrored な glob ターゲット/サブツリー内ファイルを glob されたサブツリーの外へ移動するか、明示的な静的インポートへ置き換えてください。なお クライアントスクリプト(*.client.ts)は import.meta.glob を一切サポートせず、しかも島とは異なり、その失敗はビルド時には検出され ません。クライアントスクリプト: import.meta.glob はサポートされていません を参照してください。
bundle.loaders または bundle.define が拒否される
症状: 設定のロードが次のようなメッセージで失敗する。
bundle.loaders key ".asset" uses unsupported loader "file"; inline-only v1 accepts: ...
bundle.define key "import.meta.env.DEV" is reserved by zfb's bundle mode ...生の define 式が不正な場合は、最初に影響を受けるバンドルの実行時に esbuild のパースエラーとして現れることもあります。
原因: loader のキーは . で始まり、text、json、base64、dataurl、binary、empty のいずれかを使い、.css、.module.css、.mdx、.md を上書きしない必要があります。アセットを生成する file と copy loader はサポートされません。また zfb は import.meta.env.DEV、import.meta.env.PROD、process.env.NODE_ENV を所有するため、ユーザーの define から置き換えることはできません。define の値は、自動的に引用符が付く文字列ではなく esbuild の生の式です。
対処: inline loader と予約されていない拡張子 / キーを選んでください。文字列の define では、置換式に JSON の引用符を含めます(例: __APP_NAME__: '"my-app"')。完全なコントラクトとブラウザへの公開に関する警告は defineConfig: bundle 設定を参照してください。
?raw インポートが失敗する
症状: build、または dev 中のブラウザバンドルの更新が、unsupported import query form、does not resolve to an existing file、is not valid UTF-8 text のいずれかを報告する。
原因: zfb がサポートするのは、リテラルのプロジェクトローカル相対ターゲットと厳密な ?raw サフィックスを持つ静的な default import だけです。ターゲットは終端の UTF-8 テキストファイルです。dynamic import、named import、namespace import、side-effect import、type-only import、re-export、?url、追加のクエリパラメータ、リテラルでないパス、ルート外 / symlink 経由の escape、UTF-8 ではないターゲットは拒否されます。
対処: import を次の形にし、厳密なファイルがプロジェクトルート内に存在することを確認してください。
import text from "./file.ext?raw";拡張子は何でもよく、bundle.loaders のエントリも不要です。Islands: ?raw でテキストをインポートする、またはクライアントスクリプトを参照してください。
Module worker が出力されない、または SharedWorker が失敗する
症状: worker constructor が書き換えられず worker-*.js companion も現れない、または build が unsupported SharedWorker を報告する。
原因: zfb は shadow されていないグローバルの Worker を、下記のリテラルな module 形式でだけ探索します。URL はクエリや fragment のない、厳密なプロジェクトローカル相対パスの JS / TS ファイルを指す必要があります。リテラルでない形式や classic worker はコントラクトの対象外です。探索は意図的にインストール済みの node_modules をたどりません。同じリテラル URL 形式を使う SharedWorker は、一見サポートされるように見える URL が書き換えられず実行時に 404 する状態を避けるため、明示的に拒否されます。
対処: first-party の dedicated worker には次の形式を使います。
const worker = new Worker(
new URL("./worker.ts", import.meta.url),
{ type: "module" },
);island の worker は /、クライアントスクリプトの worker は / に置かれます。書き換え後の URL はその安定名を維持し、厳密に 8 文字の小文字 16 進数である ?v= グラフハッシュを追加します。サポートされない形式や third-party の推移的 worker は、パッケージ固有のツールでバンドルしてください。Islands: Module workerを参照してください。
プロジェクトルート外への相対インポートが "Could not resolve" になる
症状: zfb build(または zfb dev)が esbuild の Could not resolve ". エラーで失敗し、付随する zfb の注記が「シャドウコピーのビルド境界」を説明する。
原因: zfb は、esbuild を実行する前にプロジェクトルートを一時ディレクトリへシャドウコピーしてビルドします。プロジェクトルートより上へ歩く相対インポート(例: .)は、そのシャドウコピーの外に解決されるため見つかりません。これは診断専用であり、解決可能なバグではありません。根本的な脱出は依然としてサポートされません。zfb は、意味のない一時ディレクトリのパスを漏らす代わりに、報告される エラーが実際の(シャドウでない)パスを示し、回避策を説明するようにするだけです。
対処: ルート外のターゲットを相対インポートではなくパッケージインポートとして公開してください。ターゲットパッケージの package.json にワイルドカードの exports エントリ(例: "./src/*": "./src/*")を追加し、パッケージ指定子でインポートします(例: @scope/)。node_modules(file:/ワークスペースリンクされたパッケージを含む)はシャドウコピーに含まれるため、パッケージ指定子のインポートは通常どおり解決されます。詳細は defineConfig: プロジェクトルート外のパスを監視する を参照してください。追跡は issue #1385 で行われています。
組み込みの zfb-server からの esbuild binary not found
症状: zfb-server を組み込んだ Rust ホスト(ライブラリとして組み込む を参照)が、config_path が zfb.config.ts ファイルを指しているときに "esbuild binary not found" エラーで失敗する。
原因: TypeScript の設定を評価するには、まずそれを esbuild でバンドルする必要がありますが、組み込みの zfb-server は zfb CLI のように自前の esbuild バイナリを同梱していません。
対処: config_path を zfb.config.json ファイルに切り替える(esbuild は一切不要 — 最もシンプルな修正)か、build() を呼び出す前に環境変数 ZFB_ESBUILD_BIN を利用可能な esbuild CLI バイナリに設定してください。完全な説明は ライブラリとして組み込む: 設定形式 を参照してください。
prerender = false のルートが常に 405 を返す
症状: SSR ルートの POST/PUT/DELETE ハンドラが、期待どおりのメソッドを使い他の点でも正しいリクエストに対してまで、常に 405 Method Not Allowed を返す。
原因: そのルートのデフォルトエクスポートが、受信した Request を受け取るつもりの仮引数を宣言している。
export default async function Handler(request: Request) {
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
// ...
}zfb がページのデフォルトエクスポートを呼ぶときに渡すのは、Request ではなくそのページの props オブジェクトです。コントラクトの全体は デフォルトエクスポートが受け取るのは props であり Request ではない を参照してください。つまり上の request の実体は {}(あるいは { params }、あるいはそのルートの paths() / getStaticProps() の props)であり、request.method は undefined を読み、undefined !== "POST" が成り立つため、ハンドラは無条件に 405 を返します。何も例外を投げず、しかも Request は props を受け取る仮引数に対しても妥当な TypeScript の型注釈なので tsc --noEmit も通ります。コンパイルはきれいに通り、実行時に静かに壊れるということです。
次のコマンドで直接検出できます。
grep -rn 'export default \(async \)\?function \w\+(\s*request\s*:' pages/対処: 仮引数を外す(あるいは実際に必要な props だけを分割代入する — { params } など)。そのうえで、本物の Request は getCloudflareContext() から読んでください。
import { getCloudflareContext } from "@takazudo/zfb-adapter-cloudflare";
export default async function Handler() {
const { request } = getCloudflareContext();
if (request.method !== "POST") {
return new Response("Method Not Allowed", { status: 405 });
}
// ...
}zfb check はこの形を検出して非ゼロで終了します。zfb dev と zfb build はビルドを失敗させずに警告します。実際の 405 を踏んだのではなくそれらの警告からここへたどり着いた場合も、原因と対処は上と同じです。
zfb の shadow ビルドディレクトリを調査したい
症状: zfb build または zfb dev が失敗する、あるいは想定外の挙動をし、その原因が esbuild に渡す前に zfb が生成するもの — 生成された injected route の shim、解決済みの node_modules レイアウト、合成された tsconfig.json — に関係していそうだと分かった。しかしプロセスが終了する頃には(ビルド失敗時であっても)、それらを保持していた一時ディレクトリはすでに消えている。
原因: zfb は該当するツリーの shadow コピーを tempfile 管理の一時ディレクトリに生成してビルドし、プロセス終了時にそれを削除します — これは通常の動作であり、後から / を探しても見つからない理由です。
対処: どちらか一方の opt-in 環境変数を設定すると、shadow ツリーを削除せずディスク上に残せます。対象となる一時ディレクトリの範囲はそれぞれ異なり、どちらも保持したディレクトリを自動では回収しません — 調査が終わったら自分で削除してください。
| 変数 | 対象 | 保持されるもの |
|---|---|---|
ZFB_KEEP_BUILD_SHADOW=1 | zfb build のみ | バンドラの shadow ルート、その exact-node_modules 分離ルート、そしてパッケージルートのオーバーレイ(プロジェクトがパッケージルートを登録している場合)。ビルド失敗時も保持されます。保持された各パスは stderr に一度だけ出力されます。zfb build: 環境変数 を参照してください。 |
ZFB_KEEP_SHADOW_SESSION=1 | zfb dev のみ | dev サーバーがプロセス全体で使い回す、唯一の永続的な shadow セッション一時ディレクトリ。このフラグを設定せずに後で zfb dev を起動すると、内部の経過時間しきい値を超えた時点で以前保持したディレクトリが回収されます — デバッグセッション全体でフラグをエクスポートし続けてください(そのディレクトリを作成した起動時だけでは不十分です)。zfb dev: 環境変数 を参照してください。 |
どちらも対象範囲は狭く限定されています。zfb build/zfb dev のすべての一時ファイル生成元を網羅しているわけではありません(設定の読み込み、islands/esbuild、CSS、プラグイン解決はどちらの対象外です)。また、一方を設定してももう一方のサブコマンドには影響しません — ZFB_KEEP_BUILD_SHADOW は zfb dev に影響せず、ZFB_KEEP_SHADOW_SESSION は zfb build に影響しません。