# 0139 — by-value self-referential type segfaults (`typeSizeBytes` infinite recursion) > **RESOLVED.** Root cause: `typeSizeBytes` (and the layout path) recursed into > each by-value aggregate field with no cycle guard, so a by-value self/mutual > reference looped to a stack overflow. Fix: a new `checkInfiniteSize` pass > (`src/ir/lower/decl.zig`, Pass 1g — after type registration, before body > lowering) walks the by-VALUE containment graph; on a back-edge it emits a loud > diagnostic (`type 'X' is infinitely sized (it contains itself by value); use a > pointer ('*X') to break the cycle`) and poisons the offending field to > `.unresolved`, breaking the recursion before any sizing runs. A pointer / slice > / optional payload breaks the cycle, so `*Self` recursion stays valid. Covers > both source decls and comptime-constructed (`declare`/`define`) types. > Regression test: `examples/1178-diagnostics-infinite-size-self-reference.sx`. **Symptom** — a type whose field/variant payload is ITSELF *by value* (not behind a pointer) crashes the compiler with a stack-overflow segfault instead of a loud "infinite size" diagnostic. Observed: `Segmentation fault` inside `src/ir/types.zig:typeSizeBytes` (unbounded self-recursion through the field loop). Expected: a clean compile error naming the offending type and suggesting `*Self`. **Pre-existing / scope** — NOT specific to the comptime `declare`/`define` metaprogramming; a hand-written SOURCE enum reproduces it identically. So the fix belongs in the general type-system size/layout path, and the comptime construction path (METATYPE F5) inherits the protection for free once it lands. **Reproduction** (source enum — no metaprogramming needed): ```sx #import "modules/std.sx"; Bad :: enum { node: Bad; // by-VALUE self-reference → infinite size leaf; } main :: () -> i32 { x : Bad = .leaf; return 0; } ``` Same crash via the metaprogramming path (`#import "modules/std/meta.sx"`): ```sx make_bad :: () -> Type { h := declare("Bad"); return define(h, .enum(.{ variants = .[ EnumVariant.{ name = "node", payload = Bad }, // by-value self-ref EnumVariant.{ name = "leaf", payload = void } ] })); } Bad :: make_bad(); ``` **Investigation prompt** — A by-value self-referential (or mutually-recursive) aggregate has infinite size and must be rejected loudly, not recursed into forever. The crash is in `src/ir/types.zig:typeSizeBytes` (~line 736), which recurses into each struct/tagged-union field's type with no cycle guard; a field typed as its own (or an enclosing) nominal type recurses unboundedly → stack overflow. Fix: detect the cycle — walk the nominal-type dependency with a visited set (or a recursion-depth / on-stack-nominal guard), and when a nominal type reaches itself by value (no pointer indirection on the path), emit a diagnostic via `self.diagnostics.addFmt(.err, span, "type '{s}' is infinitely sized (it contains itself by value); use a pointer (`*{s}`) to break the cycle", …)` and return a sentinel size (e.g. 0 with the error already raised, or poison) rather than recursing. A pointer field (`*Bad`) breaks the cycle and must stay allowed (pointers have a fixed size and don't recurse into the pointee). Verification: run the repro above — expect the loud diagnostic + non-zero exit, NOT a segfault. Add an `examples/11xx-diagnostics-*` (or `issues/`) pin once the message is settled. This also closes METATYPE PLAN F5's "by-VALUE self-reference rejected" item for the comptime path.