Debugging Constraints
Rezi constraint failures are deterministic: there are no silent fallbacks and no “best effort” coercions.
Rezi constraint failures are deterministic: there are no silent fallbacks and no “best effort” coercions.
This guide is a diagnosis flow for the most common constraint/layout failures.
See also:
docs/guide/constraints.mddocs/reference/constraint-expressions.mddocs/dev/live-pty-debugging.md(frame-audit workflow)
1) Identify the error class
ConstraintSyntaxError (parse-time)
Cause: invalid DSL syntax in expr("...").
Fix:
- Correct the expression string
- Prefer helper constraints to avoid hand-typed syntax for common patterns
ZRUI_INVALID_CONSTRAINT (frame-time)
Common causes:
- Unknown function name (typo):
clmp(...) - Unknown widget ref:
#sidebr.w - Ambiguous direct widget ref when ids are shared
- Invalid
max_sibling/sum_siblingusage
Fix:
- Check the expression source in the error detail
- If you intended a common pattern, replace it with a helper from
docs/reference/constraints-api.md
ZRUI_CIRCULAR_CONSTRAINT (frame-time)
Cause: a cycle in dependency graph (often mutual sibling width references).
Fix:
- Anchor one side of the relationship to
parent.*,viewport.*, orintrinsic.* - Avoid
#a→#band#b→#aloops
ZRUI_INVALID_PROPS
Cause: prop contract violations, for example:
%size strings- responsive-map layout constraints (
{ sm, md, ... }) grid.columns: expr(...)(invalid in alpha)
Fix:
- Migrate to helper constraints /
exprwhere supported - Use multiple grids and switch with
displayfor responsive columns
2) Narrow down the source
Practical steps:
- Search for
expr("usages near the failing widget - Check for
#id.*references and confirm the referenced ids exist in the same committed tree - Confirm direct
#id.*targets are unique (usemax_sibling/sum_siblingfor shared ids) - For
max_sibling/sum_sibling, confirm the matching ids are siblings under the same parent as the consumer - Reduce the expression to a simpler form to isolate which term is invalid
3) Use deterministic runtime evidence (frame audit)
For hard-to-reproduce visual glitches, use the PTY + frame-audit workflow:
REZI_FRAME_AUDIT=1 REZI_FRAME_AUDIT_LOG=/tmp/rezi-frame-audit.ndjson node <your-app>
node scripts/frame-audit-report.mjs /tmp/rezi-frame-audit.ndjson --latest-pidThis helps confirm whether layout/renderer diverges across frames, and provides stage-level counters.
4) Use the dev inspector overlay (constraints instrumentation)
Rezi can surface constraint graph + resolved values in the dev inspector overlay.
Enable it by using createAppWithInspectorOverlay(...) (default toggle hotkey is ctrl+shift+i):
import { createAppWithInspectorOverlay } from "@rezi-ui/core";
import { createNodeBackend } from "@rezi-ui/node";
const app = createAppWithInspectorOverlay({
backend: createNodeBackend(),
initialState: { /* ... */ },
});What you’ll see:
constraints:graph node count, hidden-by-display count, and whether the last resolution was reused / cache hit / computed.constraints_focus:resolved constraint values for the currently focused widget id (if present in the constraint graph).constraints_exprs:the constraint expressions that apply to that focused widget instance (truncated).
Notes:
- If an
idis shared by multiple widgets, the overlay reportsinstances=Nand shows one instance. Prefer unique ids when debugging. - This instrumentation is intended for development (it adds per-frame bookkeeping and allocations).
5) Recognize common constraint bugs
- Wrong
clamp(...)argument order: Rezi usesclamp(min, value, max). - Assuming boolean operators exist: the DSL does not support
&&/||; useif(...)or ternary. - Creating “invisible dependencies”: referencing a widget that is conditionally omitted via
show(...)can invalidate sibling refs.