---
title: "トラブルシューティング — zenit Zig UI ドキュメント"
description: "ビルドエラーから状態のライフタイム、描画の不具合まで、最短経路で原因を特定します。"
url: https://zenit.z.express/ja/docs/reference/troubleshooting
language: ja
alternate_en: https://zenit.z.express/docs/reference/troubleshooting.md
alternate_zh: https://zenit.z.express/zh/docs/reference/troubleshooting.md
alternate_es: https://zenit.z.express/es/docs/reference/troubleshooting.md
alternate_ko: https://zenit.z.express/ko/docs/reference/troubleshooting.md
alternate_fr: https://zenit.z.express/fr/docs/reference/troubleshooting.md
alternate_de: https://zenit.z.express/de/docs/reference/troubleshooting.md
project: zenit v0.1.0-alpha (Zig 0.15.2, macOS)
source: https://github.com/version-next/zenit
---

# トラブルシューティング

ビルドエラーから状態のライフタイム、描画の不具合まで、最短経路で原因を特定します。

## ビルドエラー

**invalid fingerprint**

テンプレートの fingerprint はそのまま再利用できません。`build.zig.zon` の `.fingerprint` 行を削除して `zig build` を一度実行し、Zig が出力した固有の値を書き戻してください。

**import of file outside module path**

フレームワーク内部のファイルに対して `zig test` を直接実行しないでください。`zig build test-ui` などリポジトリで定義されたテスト step を使います（[コマンド一覧](https://zenit.z.express/ja/docs/reference/commands)を参照）。

**@import("ui") / @import("zenit_app") not found**

`build.zig.zon` で `.zenit` 依存が宣言されていること、そして executable の作成後に `zenit.attach(zenit_dep, exe)` を呼んでいることを確認してください。これが `ui` / `zenit_app` モジュールの追加、macOS ブリッジのコンパイル、システムフレームワークのリンクを行います。

**build API field mismatch**

まず `zig version` を実行してください。zenit は Zig 0.15.2 を必要とします（`build.zig.zon` の `minimum_zig_version`）。他のバージョンの build API はサポート対象外です。

**-Dtest-mode=true has no effect**

Zig の依存オプションは分離されています。`b.dependency("zenit", ...)` で `.@"test-mode"` と `.@"e2e-port"` を明示的に転送してください。`templates/minimal-app/build.zig` が参考になります。

## 実行時と状態

**error.StateNotFound**

明示的な ID を使う `cx.handler(State, id, method)` が、対応する state の作成前に呼ばれています。`cx.bindState` + `cx.on` を優先してください。状態ポインタを直接渡すので、ID を管理する必要がありません。

**leaked ArrayList / HashMap at exit**

`bindState` の状態は Cx が所有し、Cx の解放時に一緒に解放されます。T が **pub** の `deinit(self: *T)` を宣言していれば、フレームワークが自動で呼び出します。リークは通常、`deinit` が pub でないか、リソースがページのライフタイムに従うべきだったことを意味します。書き方は次のセクションを参照してください。

**crash after switching pages**

グローバル状態に前のページの `*Node` や `*Scope` を保存していないか確認してください。ページの Scope が dispose されると、これらのポインタはすべて無効になるため、同時にクリアする必要があります。

**Invalid free after updating text**

ノードの現在のテキストは、ノード自身が所有するコピーかもしれません。`getText()` で得た props の `content` を書き換えて `setText` で戻さないでください。`try node.setTextContent(cx.allocator, "Updated")` を使えば、文字列がコピーされ所有権も正しくマークされます。

## 状態の正しいクリーンアップ

状態に allocator フィールドを持たせ、pub の `deinit` 自身にクリーンアップを任せます。初期値はまだリソースを持っていてはいけません。`bindState` の後で確保してください。

`state_deinit.zig`

```zig
const Editor = struct {
    allocator: std.mem.Allocator,
    lines: std.ArrayList([]const u8) = .empty,

    // pub: the Cx calls this automatically when it frees the state.
    pub fn deinit(self: *Editor) void {
        self.lines.deinit(self.allocator);
    }
};

// The initial value must not own resources yet; allocate after binding.
const editor = try cx.bindState(Editor, .{ .allocator = cx.allocator });
```

`scope.onCleanup` を使うのは 2 つの場合だけです。クリーンアップ関数が pub の `deinit` でないとき、またはリソースが Cx 全体ではなく特定の Scope（ページ）のライフタイムに従うべきときです。

`scope_cleanup.zig`

```zig
// Resources that must follow a page (Scope), not the whole window (Cx).
const PageCache = struct {
    allocator: std.mem.Allocator,
    map: std.StringHashMapUnmanaged(u32) = .empty,

    // Not named `pub fn deinit`: the Cx would call it again and double-free.
    fn release(self: *PageCache) void {
        self.map.deinit(self.allocator);
    }
};

const cache = try cx.bindState(PageCache, .{ .allocator = cx.allocator });
try scope.onCleanup(PageCache, cache, PageCache.release);
```

> WARNING
> 
> **deinit を二重に登録しないでください。** T がすでに pub の `deinit` を持っているのに、同じ関数を `scope.onCleanup` で登録すると二重解放になります。Scope の dispose 時に 1 回、Cx が状態を解放するときにもう 1 回呼ばれるためです。

## レイアウトと描画

**state changed but the text did not**

`setText` 自体が新旧のシグネチャを比較し、必要に応じて sizing / render dirty をマークするので、手動の `markRenderDirty` は不要です。テキストが更新されないのは、たいてい `TextProps` のコピーを書き換えて `setText` を呼んでいないか、表示中の値が対応する Signal を購読していないためです。`ui.textFmt(cx, scope, fmt, .{ signals }, props)` で Signal / Memo を直接購読する方法をおすすめします。

**some colors ignore a theme switch**

`boxStyled` / `textStyled` などのコンストラクタは `on_theme` hook を付けますが、`cx.setTheme` がそれを再実行するのは `cx.root` のサブツリーだけです。通常のノードやコンポーネントライブラリのスタイルは mount 時のスナップショットです。テーマ切り替え時に該当するツリーを再構築するか、Effect 内で `cx.themeSignal(scope)` を購読してスタイルを更新してください。`cx.root` 配下にないノードも更新されません。

**clicks fall through an overlay’s empty area**

インタラクションを持たない純粋に視覚的なコンテナは、既定で `pass_through` です。オーバーレイのルートノードのスタイル拡張に `hit_behavior = .@"opaque"` を設定するか、barrier を内蔵した [Modal](https://zenit.z.express/ja/components/modal) / [Sheet](https://zenit.z.express/ja/components/sheet) を使ってください。

**a huge invisible hit area in the window**

`ui.devtools.overlay` をアタッチしてヒットしているノードを調べ、`node.globalRect()` でその画面上の rect を出力します。原因はたいてい親コンテナの fill / grow 設定か、大きすぎる絶対配置の範囲です。オーバーレイが非表示のときも、ヒットテストから外れているか確認してください。`node.setDisplay(.none)` で隠したサブツリーは、レイアウト・描画・ヒットテスト・Tab 移動からまとめて外れます。

`opaque_overlay.zig`

```zig
// Plain visual containers are pass-through by default.
// Make an overlay root swallow clicks on its empty area:
(try panel.style.ensureExtFallible(cx.allocator)).hit_behavior = .@"opaque";
```

## それでも解決しない場合

issue を報告するときは、少なくとも以下を添えてください。

-   **バージョン**：zenit の revision、`zig version`、macOS のバージョン。
    
-   **再現**：最小の再現コードと実行した build step。
    
-   **出力**：最後の 1 行だけでなく、完全なエラー出力。
    
-   **描画の問題**：スクリーンショットと、DevTools で確認した関連ノードのサイズ。
