---
title: "Dépannage — Docs zenit Zig UI"
description: "Des erreurs de build à la durée de vie de l’état et aux défauts de rendu — le chemin le plus court vers la cause."
url: https://zenit.z.express/fr/docs/reference/troubleshooting
language: fr
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_ja: https://zenit.z.express/ja/docs/reference/troubleshooting.md
alternate_ko: https://zenit.z.express/ko/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
---

# Dépannage

Des erreurs de build à la durée de vie de l’état et aux défauts de rendu — le chemin le plus court vers la cause.

## Erreurs de build

**invalid fingerprint**

La fingerprint d’un template ne peut pas être réutilisée. Supprimez la ligne `.fingerprint` de `build.zig.zon`, lancez `zig build` une fois, puis recollez la valeur unique affichée par Zig.

**import of file outside module path**

N’exécutez pas `zig test` directement sur des fichiers internes du framework. Utilisez les steps de test du dépôt, comme `zig build test-ui` (voir [Commandes](https://zenit.z.express/fr/docs/reference/commands)).

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

Vérifiez que `build.zig.zon` déclare la dépendance `.zenit` et que vous appelez `zenit.attach(zenit_dep, exe)` après avoir créé l’exécutable — c’est lui qui ajoute les modules `ui` / `zenit_app`, compile les ponts macOS et lie les frameworks système.

**build API field mismatch**

Lancez d’abord `zig version`. zenit requiert Zig 0.15.2 (`minimum_zig_version` dans `build.zig.zon`) ; les build API des autres versions ne sont pas prises en charge.

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

Zig isole les options des dépendances. Transmettez explicitement `.@"test-mode"` et `.@"e2e-port"` dans `b.dependency("zenit", ...)`, comme le fait `templates/minimal-app/build.zig`.

## Exécution et état

**error.StateNotFound**

Un `cx.handler(State, id, method)` à id explicite s’est exécuté avant que cet état n’existe. Préférez `cx.bindState` + `cx.on` : ils passent directement le pointeur d’état, sans id à gérer.

**leaked ArrayList / HashMap at exit**

L’état issu de `bindState` appartient au Cx et est libéré avec lui ; si T déclare un `deinit(self: *T)` **pub**, le framework l’appelle automatiquement. Une fuite signifie en général que `deinit` n’est pas pub, ou que la ressource aurait dû suivre la durée de vie d’une page. Voir la section suivante.

**crash after switching pages**

Cherchez un `*Node` ou un `*Scope` de la page précédente conservé dans un état global. Une fois le Scope de la page libéré, ces pointeurs sont invalides et doivent être effacés avec lui.

**Invalid free after updating text**

Le texte actuel du nœud peut être une copie qu’il possède. Ne modifiez pas `content` sur les props issues de `getText()` pour les repasser à `setText` ; utilisez `try node.setTextContent(cx.allocator, "Updated")`, qui copie la chaîne et marque correctement la propriété.

## Nettoyer l’état correctement

Gardez un champ allocator dans l’état et laissez un `deinit` pub faire le nettoyage. La valeur initiale ne doit encore posséder aucune ressource — allouez après `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 });
```

N’utilisez `scope.onCleanup` que si le nettoyage n’est pas un `deinit` pub, ou si la ressource doit suivre un Scope (une page) plutôt que le Cx entier.

`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
> 
> **N’enregistrez pas deinit deux fois.** Si T a déjà un `deinit` pub, enregistrer la même fonction avec `scope.onCleanup` provoque une double libération : une fois à la libération du Scope, et une autre quand le Cx libère l’état.

## Layout et dessin

**state changed but the text did not**

`setText` compare déjà l’ancienne et la nouvelle signature et marque sizing / render dirty si nécessaire — pas besoin de `markRenderDirty` manuel. Un texte figé signifie en général qu’une copie de `TextProps` a été modifiée sans appeler `setText`, ou que la valeur affichée ne s’est jamais abonnée à son Signal. Préférez `ui.textFmt(cx, scope, fmt, .{ signals }, props)` pour vous abonner directement aux Signals / Memos.

**some colors ignore a theme switch**

`boxStyled` / `textStyled` et consorts attachent un hook `on_theme`, et `cx.setTheme` ne les rejoue que dans le sous-arbre de `cx.root` ; les nœuds simples et les styles de composants sont des instantanés pris au mount. Reconstruisez ces arbres lors d’un changement de thème, ou abonnez-vous à `cx.themeSignal(scope)` dans un Effect et réappliquez les styles ; les nœuds non attachés sous `cx.root` ne sont pas mis à jour non plus.

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

Les conteneurs purement visuels sans interaction sont `pass_through` par défaut. Définissez `hit_behavior = .@"opaque"` sur l’extension de style de la racine de l’overlay — ou utilisez [Modal](https://zenit.z.express/fr/components/modal) / [Sheet](https://zenit.z.express/fr/components/sheet), qui apportent leur propre barrière.

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

Attachez `ui.devtools.overlay` pour inspecter le nœud touché, et affichez son rect à l’écran avec `node.globalRect()`. La cause habituelle est un sizing fill / grow du parent ou un positionnement absolu trop grand ; pour les overlays masqués, vérifiez qu’ils sont retirés du hit-testing — un sous-arbre masqué avec `node.setDisplay(.none)` quitte entièrement le layout, le dessin, le hit-testing et le parcours au 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";
```

## Toujours bloqué

Quand vous ouvrez une issue, joignez au minimum :

-   **Versions** : la révision de zenit, `zig version` et votre version de macOS.
    
-   **Reproduction** : un exemple minimal et le build step lancé.
    
-   **Sortie** : la sortie d’erreur complète, pas seulement la dernière ligne.
    
-   **Problèmes de rendu** : une capture d’écran et la taille des nœuds concernés relevée dans DevTools.
