Diagnostics#
Every ww::stage::name code a compile can report, scanned from the compiler's sources. A scene carries them in diagnostics with a severity, the line, and the message. Where the stage declares a message template, it is shown ({braces} are filled in at run time) with its help line.
Stage analysis#
ww::analysis::unaccounted_contact#
Reported by the compiler with a message built at run time.
Stage check#
ww::check::below_floor#
Reported by the compiler with a message built at run time.
ww::check::empty_assembly#
Reported by the compiler with a message built at run time.
ww::check::extra_root#
Reported by the compiler with a message built at run time.
ww::check::floating#
Reported by the compiler with a message built at run time.
ww::check::slide_clearance#
Reported by the compiler with a message built at run time.
ww::check::travel_foul#
Reported by the compiler with a message built at run time.
ww::check::travel_invalid#
Reported by the compiler with a message built at run time.
ww::check::travel_unchecked#
Reported by the compiler with a message built at run time.
Stage dsl#
ww::dsl::bad_choice#
A choice set to a word its declaration does not allow, or declared without words. Message: choice `{choice}`: {problem}
Help: {allowed}
ww::dsl::bad_import_path#
Message: `{path}` is not a usable import path
Help: `from=` is `std:name` for an embedded library, or a `/`-separated path relative to this file
ww::dsl::bad_reference#
Message: `{raw}` is not a valid reference
Help: a reference is `Part@Mark` (ADR-0002); either half may interpolate a name in braces (`Rail_{i}@Slot_{i}`), but braces must pair up around it
ww::dsl::bad_value#
Message: `{node}` has a `{key}` of the wrong type
Help: expected {expected}
ww::dsl::collection_cycle#
Message: collections extend each other in a cycle: {chain}
Help: `extends=` must lead back to a collection with no `extends=`
ww::dsl::collection_unknown_key#
A derived collection setting a param, choice or slot its bases never declared. Message: collection `{collection}` sets {what} `{name}`, which `{base}` does not declare
Help: a derived collection lists only differences; declare it in the base collection first
ww::dsl::duplicate#
Message: `{name}` is declared more than once in this scope
ww::dsl::import_conflict#
Message: import conflict: {what}
Help: {hint}
ww::dsl::import_cycle#
Message: import cycle: {chain}
Help: a file cannot import itself, directly or through others
ww::dsl::import_load_failed#
Message: cannot import `{path}`: {reason}
ww::dsl::import_too_deep#
[crate::Limits::max_import_depth]. Message: imports chain more than {limit} files deep
Help: a chain of files importing files may be at most {limit} long (docs/KDL_AUTHORING.md §13)
ww::dsl::kdl_syntax#
Message: file does not parse as KDL v2
Help: woodwerx uses KDL v2. Note that `(` after `=` starts a type annotation, not a tuple, and backtick is a legal identifier character (ADR-0002).
ww::dsl::missing_field#
Message: `{node}` is missing {what}
ww::dsl::missing_project#
Message: expected a single top-level `project` node
ww::dsl::nothing_exported#
Message: `{path}` exports nothing
Help: a file opts in to being imported by writing `export=Name` on a top-level `assembly` or `component`
ww::dsl::slot_contract#
A slot bound to something that is missing, of the wrong kind, or lacks a param the slot's contract names. Points at the collection line that made the binding. Message: slot `{slot}` of collection `{collection}`: {problem}
Help: a slot binds a name of its kind, and a component or assembly slot must declare every param in its `requires=`
ww::dsl::source_too_large#
[crate::Limits::max_source_bytes]. Checked before the file is parsed at all. Message: the file is {size} bytes; the limit is {limit}
Help: a project file may be at most {limit} bytes (docs/KDL_AUTHORING.md §13). The largest example is about a sixth of that
ww::dsl::too_deep#
[crate::Limits::max_depth], counted in { … } blocks. Checked before the file is parsed, because the KDL parser recurses once per level. Message: blocks nest more than {limit} deep
Help: `{ … }` blocks may nest at most {limit} levels, counting `project` as the first (docs/KDL_AUTHORING.md §13)
ww::dsl::too_many_imports#
[crate::Limits::max_imports]. Message: more than {limit} distinct files imported
Help: a project may pull in at most {limit} distinct files (docs/KDL_AUTHORING.md §13)
ww::dsl::unexpected_entry#
An argument or property in a slot the typed IR has nowhere to put. Stage 1 reports these rather than discarding them: silently dropping a property the author wrote is how a file compiles into something other than what it says. Message: `{node}` does not take {what}
Help: {expected}
ww::dsl::unexpected_node#
Message: `{node}` is not valid at this scope
Help: {expected}
ww::dsl::unknown_collection#
project collection=X or extends=X naming a collection that does not exist. Message: no collection named `{name}`
Help: {available}
ww::dsl::unknown_export#
Message: `{path}` does not export `{name}`
Help: it exports: {available}
ww::dsl::unknown_slot#
@name where no slot of that name is in force. Message: no slot `@{name}` in force
Help: {available}
ww::dsl::unknown_unit#
A (unit) annotation on a number that is not mm or in (ADR-0021). Message: `({unit})` is not a known unit
Help: the unit annotations are `(mm)` and `(in)`; bare numbers are millimetres
Stage eval#
ww::eval::cel_runtime#
Message: expression could not be evaluated
ww::eval::cel_syntax#
Message: expression is not valid CEL
Help: {hint}
ww::eval::cycle#
Message: `{name}` is defined in terms of itself
Help: the cycle is: {cycle}
ww::eval::expression_too_complex#
An expression has more operators and brackets than [crate::guard::MAX_EXPR_OPERATORS] — a bound on how deep its tree can nest, which cel walks recursively. Checked before it is parsed. Message: expression has {count} operators and brackets
Help: at most {limit} in one expression; split it into named parameters
ww::eval::expression_too_long#
An expression's source text is longer than [crate::guard::MAX_EXPR_BYTES]. Checked before it is parsed. Message: expression is {len} bytes long
Help: at most {limit} bytes; split it into named parameters
ww::eval::fractional_count#
Message: `count` is {value}, so this `repeat` runs {iterations} time(s)
Help: `repeat count=` is floored (ADR-0005). Write `ceil(…)` for {next_up}, or make the count come out whole
ww::eval::link#
A linked parameter (solves= / inverse=, ADR-0035) that cannot work: the target is derived, the link loops, or the inverse reads what it is trying to set. Message: `{name}` is a badly linked parameter: {message}
Help: a linked parameter is a derived one whose `solves=` names a literal parameter it depends on; see docs/adr/0035-linked-parameters.md
ww::eval::non_positive#
Message: `{name}` is {value}, which is not a positive dimension
ww::eval::not_finite#
Message: `{name}` evaluates to {value}
Help: a dimension must be a finite number; check for a division by zero
ww::eval::not_in_language#
Something CEL parses but woodwerx's expression language does not include: a comprehension macro, a method call, a list or map, field selection. See [crate::guard]. Message: {construct} is not part of woodwerx's expression language
Help: {hint}
ww::eval::out_of_range#
Message: `{name}` is {value}, outside its declared range {min}..={max}
ww::eval::repeat_count_too_large#
repeat count= resolved to more iterations than Stage 2 will enumerate. Stage 2 binds the loop index for each iteration, so a count is a bound on work. A furniture project does not have ten thousand of anything; a count that large is a units mistake or a runaway expression, and diagnosing it beats hanging. Message: `repeat` asks for {count} iterations
Help: at most {limit} are resolved; check the units on this count
ww::eval::text_too_long#
An expression can build text longer than [crate::guard::MAX_TEXT_BYTES]. Usually found before evaluation, from the lengths of what the expression concatenates, in which case len is that upper bound. Message: `{name}` can build {len} bytes of text
Help: text in an expression is limited to {limit} bytes
ww::eval::too_many_instances#
Limits::max_parts, reached by nested repeats: this one's count times every enclosing one's. Diagnosed before the loop is unrolled, not after. Message: nested `repeat`s unroll to {product} instances; the limit is {limit}
Help: this count multiplied by every enclosing `repeat`'s is {product}; a project may expand to at most {limit} parts (docs/KDL_AUTHORING.md §13)
ww::eval::too_many_parts#
Limits::max_parts, reached by the part nodes walked with every repeat unrolled. Resolution stops here. Message: more than {limit} `part`s, counting each `repeat` iteration
Help: a project may expand to at most {limit} parts (docs/KDL_AUTHORING.md §13)
ww::eval::too_many_specialisations#
Limits::max_specialisations: distinct override sets across instances of assemblies. Message: more than {limit} distinct assembly specialisations
Help: each distinct set of overrides on an `instance=` of an assembly is one specialisation; at most {limit} (docs/KDL_AUTHORING.md §13). An assembly that instances itself with changing overrides never settles
ww::eval::unknown_name#
Message: unknown name `{name}`
ww::eval::unknown_override#
Message: `{key}` is not a parameter of `{component}`
Help: {}`{component}` declares no parameters, so it has nothing to override`{component}` declares: {},
ww::eval::unsupported_operator#
An operator CEL parses but woodwerx's numeric domain cannot apply. The one that matters is %: cel reports it as UnsupportedBinaryOperator("rem", Float, Float), which tells an author writing shelf_pitch % 2.0 nothing at all. No example in examples/ uses it outside a comment, but an author will. Message: `{op}` cannot be used on dimensions
Help: {hint}
Stage expand#
ww::expand::assembly_anchor#
An assembly has no stock box, so of D6's anchors only the origin means anything. Message: an assembly instance cannot be anchored `by {anchor}`
Help: an assembly has no board to take a bounding-box anchor from, so it is placed by its own origin: `by top_sw`, or no `by` at all. Move the parts inside the assembly instead
ww::expand::bad_dimension#
Message: `{what}` is {value}, which cannot be a dimension
Help: a board has three finite, positive extents (D4)
ww::expand::bad_interpolation#
Message: `{text}` cannot be interpolated
Help: {help}
ww::expand::bad_mark#
Message: `mark` needs {what}
ww::expand::bad_mirror#
RFC-0012 / proposal 0202: mirror reflects across exactly one axis. Message: `mirror` needs {what}
Help: `mirror` reflects the part across the plane `<axis> = <value>` in the parent frame: exactly one of `x=`, `y=` or `z=` (RFC-0012, proposal 0202)
ww::expand::bad_normal#
Message: `{found}` is not a face direction
Help: `normal=` is one of pos_x neg_x pos_y neg_y pos_z neg_z, pointing out of the material (D6)
ww::expand::bad_stock#
Message: `stock` is malformed
Help: {help}
ww::expand::bad_travel#
A travel child of a join that cannot be read (ADR-0075). Message: bad `travel`: {detail}
Help: `travel [kind=slide|angle] [axis=x|y|z, optionally -signed] [min=] [max=] [rest=] [step=] [body=part|assembly] [pivot=<mark>]`
ww::expand::duplicate_axis#
pos x=1 x=2: KDL keeps the last, and the first would be lost without a word. Message: `{node}` gives `{key}=` twice
Help: each of `x=`, `y=`, `z=` appears at most once on a `{node}`; the second would silently replace the first
ww::expand::duplicate_id#
Message: `{id}` names two things in one assembly
Help: ids are unique among the parts and sub-assemblies of one assembly. Inside a `repeat`, interpolate the loop variable: `id="Name_{i}"`
ww::expand::duplicate_mark#
Message: mark `{name}` is declared more than once on one part
ww::expand::duplicate_node#
Message: `{node}` is given more than once
ww::expand::inline_override#
Message: `{key}` is not a parameter — part `{id}` instantiates no component
Help: only a component instance takes parameter overrides; an inline part's expressions see the enclosing scope directly
ww::expand::instance_cycle#
Message: assembly `{name}` contains itself
Help: the chain is: {cycle}
ww::expand::instance_with_stock#
Message: part `{id}` has both `instance=` and its own `stock`
Help: a `part` either instantiates a component or carries an inline `stock`, never both (docs/KDL_AUTHORING.md §9). The component's `stock` is the board
ww::expand::material_refusal#
ADR-0076: a substance= / tempered= that is malformed, or a feature the material cannot take (a cut in tempered glass). Message: a material cannot be made or cut that way
ww::expand::missing_stock#
Message: {what} has no `stock`
Help: every part is cut from a board: `stock <material> <x> <y> <z> [grain]` (ADR-0007)
ww::expand::not_a_number#
Message: `{what}` is {found}, not a number
ww::expand::not_a_part#
Message: `{part}` is a sub-assembly, not a part
Help: a join mates two boards; name a part inside the sub-assembly from within it
ww::expand::not_text#
RFC-0122's finish=: a genuine string literal needs the CEL single-quote escape hatch (ADR-0004) — finish "'danish oil'", not finish "danish oil", which CEL reads as an (unknown) identifier. Message: `{what}` is {found}, not text
Help: a genuine string literal is a CEL expression that evaluates to one: `finish "'danish oil'"`, not `finish "danish oil"` (ADR-0004)
ww::expand::one_sided_join#
join joint=X male=Part@Mark with no female=, for a joinery that joins two parts (RFC-0128, ADR-0030): only a hardware_mount mounts onto one. Message: `join joint={joint}` names no `female=`, but a `{kind}` joint joins two parts
Help: only a `hardware_mount` joinery may be fired with `male=` alone (one item on one part)
ww::expand::skeleton#
ADR-0081: a malformed locus, a part … in= naming an unresolved locus, a trimmed_by { … }/outline that cannot be reconciled with its carrier, a joints { rule … } that is malformed or ambiguous, or a structural contact joints {} does not cover. One catch-all variant, like BadStock: the message and help carry the specifics, which differ by case far more than they repeat. Message: {message}
Help: {help}
ww::expand::stray_argument#
A bare word where only x=/y=/z= belong: nearly always a second node written on the same line (pos x=1 mirror x=2), which KDL reads as one pos carrying the argument mirror and a repeated x=. Refused rather than silently misplaced. Message: `{node}` takes no bare argument, but `{found}` was written after it
Help: {help}
ww::expand::too_deep#
Limits::max_depth, counted in assemblies: a root, every assembly nested inside it, and every sub-assembly placed with instance=, all the way down. Diagnosed before anything is placed, and before the check itself recurses past the limit. Message: assemblies nest more than {limit} deep
Help: counting nested `assembly` blocks and sub-assemblies placed with `instance=`, a part may sit at most {limit} assemblies deep (docs/KDL_AUTHORING.md §13)
ww::expand::too_many_parts#
Limits::max_parts, counted with every sub-assembly instance multiplied out. Diagnosed from per-assembly counts, before any part is placed. Message: the project places {total} parts; the limit is {limit}
Help: a project may expand to at most {limit} parts, counting every part each `instance=` of a sub-assembly places (docs/KDL_AUTHORING.md §13)
ww::expand::unexpected_node#
Message: `{node}` is not valid here
Help: {expected}
ww::expand::unexpected_property#
Message: `{node}` does not take `{key}`
Help: {expected}
ww::expand::unknown_anchor#
Message: `{name}` is not one of the standard anchors
Help: D6's anchors are top_/bottom_ followed by sw, se, ne, nw, n, s, e, w or center, plus `center` for the body centre
ww::expand::unknown_hardware#
hardware_use <Name> naming no hardware catalogue item (ADR-0017). Message: `{name}` is not a declared hardware item
Help: {help}
ww::expand::unknown_instance#
Message: `{name}` is not a component or a top-level assembly
Help: `instance=` names a `component`, or an `assembly` declared at the top level
ww::expand::unknown_interpolation#
Message: `{name}`, interpolated in `{text}`, names nothing in scope
Help: `{…}`/`<…>` interpolates a name visible where the id is written — usually a `repeat` variable. It is a name, not an expression
ww::expand::unknown_joint#
Message: `{name}` is not a declared joinery
Help: {help}
ww::expand::unknown_mark#
Message: part `{part}` has no mark `{mark}`
Help: {help}
ww::expand::unknown_material#
Message: `{name}` is not a declared material
Help: {help}
ww::expand::unknown_part#
Message: no part `{part}` for `{part}@{mark}`
Help: {help}
Stage joinery#
ww::joinery::not_yet_synthesized#
Reported by the compiler with a message built at run time.
Stage lattice#
ww::lattice::degenerate_grid#
Message: `lattice rows={rows} cols={cols}` needs both at least 1
Help: `rows`/`cols` count compartments (§6.8): at least one of each
ww::lattice::missing_prop#
Message: `lattice` has no `{key}=`
Help: `lattice` needs `rows=`, `cols=`, `bar_th=`, `wall_height=`, `fit_clearance=`, `border_th=`, `inner_width=` and `inner_length=`, all literal numbers
ww::lattice::non_literal_prop#
Message: `lattice`'s `{key}=` must be a literal number, not a CEL expression
Help: the grid's own shape (how many parts/joins exist) is decided before any CEL expression is evaluated (docs/superpowers/plans/2026-10-29-drawer-dividers-698-plan.md): write the resolved number directly
ww::lattice::omit_out_of_range#
Message: `omit {form}` names a grid line outside the lattice
Help: a single-coordinate `omit x= y=` needs `x` in `1..cols-1` and `y` in `1..rows`; a region `omit from_x= from_y= to_x= to_y=` needs its bounds inside `0..cols` and `0..rows`
Stage length#
ww::length::ambiguous#
Reported by the compiler with a message built at run time.
ww::length::bad_fraction#
Reported by the compiler with a message built at run time.
ww::length::bad_number#
Reported by the compiler with a message built at run time.
ww::length::bad_unit#
Reported by the compiler with a message built at run time.
ww::length::empty#
Reported by the compiler with a message built at run time.
ww::length::out_of_range#
Reported by the compiler with a message built at run time.
ww::length::zero_denominator#
Reported by the compiler with a message built at run time.
Stage link#
ww::link::inverse#
Reported by the compiler with a message built at run time.
Stage lower#
ww::lower::wasteful_stock#
Reported by the compiler with a message built at run time.
Stage override#
ww::override::conflict#
Reported by the compiler with a message built at run time.
ww::override::derived#
Reported by the compiler with a message built at run time.
ww::override::inverse#
Reported by the compiler with a message built at run time.
ww::override::inverse_unknown#
Reported by the compiler with a message built at run time.
ww::override::length#
Reported by the compiler with a message built at run time.
ww::override::range#
Reported by the compiler with a message built at run time.
ww::override::step#
Reported by the compiler with a message built at run time.
ww::override::type#
Reported by the compiler with a message built at run time.
ww::override::unknown#
Reported by the compiler with a message built at run time.
ww::override::unresolved#
Reported by the compiler with a message built at run time.
Stage plan#
ww::plan::ambiguous_ref#
Message: `{name}` is ambiguous in this plan
Help: {detail}
ww::plan::cladding_of_edge#
Message: `of={name}` names an `edge`, not a `wall`
Help: an `edge` bounds a room without being a wall and has no face to clad
ww::plan::cladding_of_shares_wall#
Message: `of={name}` names a `shares=`'d wall, which has no face of its own
Help: a `shares=`'d wall has no endpoints of its own to build a face from (RFC-0154's own adversarial review, item 5, left open) — clad the wall it shares, or the other room's own side of it, if that has an exterior face
ww::plan::cladding_of_unknown_wall#
Message: `of={name}` names no wall of this room
Help: `cladding`'s `of=` must name one of this room's own `wall` sides
ww::plan::clearance_outside_room#
Reported by the compiler with a message built at run time.
ww::plan::clearance_overlap#
Reported by the compiler with a message built at run time.
ww::plan::clearance_too_close#
Reported by the compiler with a message built at run time.
ww::plan::cover_of_forward_layer#
Message: `of={name}` names a layer declared later (or self) in this room
Help: `cover`/`upstand`'s `of=` must name a layer already declared earlier in the same room (#656 §2.3)
ww::plan::cover_of_wrong_body#
Message: `of={name}` names a `{kind}`-bodied layer, which `cover`/`upstand` cannot derive a footprint from
Help: `cover`/`upstand` derive a footprint from a layer's placed geometry, which only a `path`-bodied layer has (#656 §2.3): `of=` must name a `path` layer, not another `cover`, `upstand` or `roof` layer
ww::plan::direction_on_freestanding_path#
Message: `direction=` on a `path` whose `{node}` leaves the room perimeter
Help: `direction=` has no meaning once a `path` leaves the perimeter — remove it, or address `{node}` with `corner=` instead (final consolidation §1/§6.1)
ww::plan::duplicate_interface#
Message: a second `interface` on this assembly
Help: an assembly may declare at most one `interface`
ww::plan::duplicate_name#
Message: `{name}` is declared more than once in this plan
Help: walls, openings, features, obstacles, runs, places and marks share one namespace per plan
ww::plan::duplicate_plan#
Message: a second `plan`/`site` in one project
Help: at most one `plan`/`site` per project (ADR-0060 Q2); a project needing two unrelated plans is two files
ww::plan::empty_layer#
Message: layer `{layer}` has no `path`
Help: a `layer` needs at least one `path` (or, once Task 5 lands, a `roof`/`cover`/`upstand`)
ww::plan::exclude_forward_instance#
Message: `exclude {name}` names an instance placed in this layer or a later one
Help: `exclude <InstanceId>` may only name an instance placed in an *earlier* layer of the same room (final consolidation §3.2)
ww::plan::expose_unknown#
Message: `expose {name}` names neither a param of `{design}` nor a project param of its file
ww::plan::fill_without_stretch#
Message: `fill` names `{design}`, which has no `stretch` param
Help: a `fill` solves a `stretch` param to close the run; expose and `stretch` one on `{design}`'s interface
ww::plan::footprint_outside#
Message: `{design}`'s built solids ({built}) reach outside its declared footprint ({footprint})
Help: the footprint is an envelope (ADR-0060 §4.6, Q8): enlarge it, or bring the build inside it
ww::plan::forward_layer_ref#
height=/offset=/anchor= naming <Layer>_bottom/_top/_height of a layer declared later (or of itself) in the same room (#653 §6.4, #647/#657 Task 3). Named ww::plan::forward_layer_ref, not ww::eval::*, deliberately: this diagnostic is part of the ww::plan::* family the rest of the layer/path grammar's diagnostics belong to (crates/ww-dsl/src/error.rs), even though the check itself can only run here — it needs Program::references().variables(), which only this crate's cel dependency provides (ww-dsl has none). Message: `{expr}` names a layer declared later in this room
Help: a `height=`/`offset=`/`anchor=` expression may only reference `<Layer>_bottom`/`_top`/`_height` of a layer declared earlier in the same room (#653 §6.4)
ww::plan::forward_path_ref#
Message: `{name}` names a path declared later (or self) in this room
Help: `path_start=`/`path_end=`/`between=` naming `{name}_start`/`{name}_end` need that path declared earlier in the same room (first synthesis §3.1)
ww::plan::layer_overflow#
A sequentially-packed segment (module doc: the independently-packed run exclude splits a path into) sums to more than the path's own available length — a wall or room-perimeter run, for a segment this module fully resolved (module doc's own "stand-in, not final" discipline: a path mixing sequential packing with an unresolved mode such as anchor= never reaches this check at all, because lower_path bails the whole path to None before any segment is measured; this variant only ever sees a segment this module is fully confident in). Message: {segment} packs to {packed_mm:.1}mm, {overshoot_mm:.1}mm past its {available_mm:.1}mm available length
ww::plan::mark_shadows_face#
Message: `mark {name}` shadows a face name
Help: a mark may not be named `front`, `back`, `left`, `right`, `top` or `bottom`: those name faces
ww::plan::missing_roof#
Message: room `{room}` has `layer`s but no `Roof` layer and no `roof_of`
Help: say so explicitly: give this room its own `layer Roof` with a `roof` child (Task 5), or `roof_of room=<RoomName>` naming the room whose roof covers it (final consolidation §3.4) — never an implicit default
ww::plan::missing_wall_thickness#
Message: wall `{wall}` bears room `{room}`'s shed roof but declares no `thickness=`
Help: the roof's bearing/seat math (2026-10-25-roof-truss-lowering-683.md) needs this wall's thickness — add `thickness=<CEL>` to `wall {wall}` (2026-10-25-wall-thickness-683.md §2); only a shed roof's `high_side=` is checked here, a gable roof's bearing walls are not yet determined structurally and so are not enforced by this diagnostic
ww::plan::mount_needs_wall#
Message: `{design}` mounts to a wall but `{place}` has neither a `run` nor an `against`
Help: a wall-mounted design needs a wall to hang from: put it in a `run`, or give it an `against <Wall>`
ww::plan::no_footprint#
Message: `interface` has no `footprint`
Help: a placeable design needs `footprint w= d= h=` (ADR-0060 §4.6)
ww::plan::no_interface#
Message: `{design}` has no `interface`
Help: only a design with an `interface` can be placed (ADR-0060 §4.6)
ww::plan::no_layer_height#
Message: layer `{layer}` has no `height=`
Help: `height=` is required on every `layer` (#653 §3): it is the layer's bottom elevation
ww::plan::not_abuttable#
Message: `{design}` has no `abut` faces, so it cannot sit mid-run
Help: declare `abut left right` (or whichever faces touch a neighbour) on `{design}`'s interface
ww::plan::not_exposed#
Message: `{key}` overrides a param `{design}` does not expose
Help: only params an `interface`'s `expose` lists may be overridden on a `place`
ww::plan::op#
Reported by the compiler with a message built at run time.
ww::plan::opening_off_wall#
Message: `{name}` sits off the end of wall `{wall}`
Help: `at=` plus `width=` must fit between the wall's two ends
ww::plan::packing_prop_outside_path#
Message: `{key}=` on a `place` that is not inside a `path`
Help: `offset_pin=`, `offset=`, `corner=`, `between=` and `anchor=` only mean something on a `place` inside a `path` (#653 §5); a `run` has its own sequential/`fill` packing
ww::plan::path_endpoint_ambiguous#
Message: more than one addressing form on this `{node}`
Help: a `path`'s `start`/`end` takes exactly one of `corner=`, `x=`/`y=`, or `path_start=`/`path_end=` (final consolidation §6.1)
ww::plan::path_endpoint_incomplete_xy#
Message: `{node}` has `{given}=` without its pair
Help: `x=` and `y=` on a `path`'s `start`/`end` must both be given (final consolidation §1/§6.1)
ww::plan::path_endpoint_off_wall#
Message: `{node}` is not on `wall={wall}`
Help: on a `wall=`-scoped `path`, `start`/`end` are interpreted as the two ends of that one wall (final consolidation §4): a `corner=` must be one of that wall's own two ends, and an `x=`/`y=` point must lie on it
ww::plan::path_wall_unknown#
Message: `wall={wall}` names no wall or edge of this room
Help: a `path`'s `wall=` must name one of the room's own `wall`/`edge` sides (final consolidation §4)
ww::plan::plan_in_import#
Message: `{path}` declares a `plan`, which an imported file cannot do
Help: plans are not importable (ADR-0060 Q15); move the `place` of this design into the importing file's own plan
ww::plan::reserved_param#
Message: `expose {name}` collides with the reserved override `{reserved}`
Help: `label`, `finish`, `mirror` and `role` are reserved on `place`; expose a different name
ww::plan::rev#
Reported by the compiler with a message built at run time.
ww::plan::roof_missing_high_side#
Message: `roof kind=shed` has no `high_side=`
Help: `high_side=<WallName>` is required for `kind=shed` (#653 §8): it names the wall the ridge runs along
ww::plan::roof_missing_ridge_axis#
Message: `roof kind=gable` has no `ridge=`
Help: `ridge=along_x|along_y` is required for `kind=gable` (#653 §8)
ww::plan::roof_mixed_with_path#
Message: a `layer` mixes `{a}` with `{b}`
Help: a `layer` uses exactly one mechanism: `path`, `roof`, `cover` or `upstand` — never more than one
ww::plan::roof_pitch_conflict#
Message: `roof` gives both or neither of `pitch=` and `rise_in_12=`
Help: exactly one of `pitch=<deg>` or `rise_in_12=<ratio>` is required
ww::plan::roof_ref_not_shared_room#
Message: `roof_of room={name}` names a room this one does not share a wall with
Help: `roof_of=` may only name a room this one is wall-connected to via `shares=` (final consolidation §3.4)
ww::plan::room_not_closed#
Message: room `{room}` is not a closed polygon
Help: the last `wall`/`edge` must return to `start x= y=`
ww::plan::room_self_intersecting#
Message: room `{room}`'s walls cross themselves
Help: list a room's sides in order round the room, either direction, with no crossing
ww::plan::shares_dimension_mismatch#
Message: `shares` wall `{name}` is a different length than `{room}.{wall}`
Help: without `span=`, a `shares`'d wall must be the same length as the wall it shares
ww::plan::shares_opening_mismatch#
Message: `shared_with`'s restated `{key}=` disagrees with `{room}.{opening}`'s own value
Help: `at=`/`width=` are optional on a `shared_with` opening (derived from the counterpart); restated anyway, they must agree (final consolidation §3.3)
ww::plan::shares_span_out_of_range#
Message: `shares`'s `span` exceeds `{room}.{wall}`'s own length
Help: `span`'s `at=`/`length=` must fit inside the named wall's own length
ww::plan::shares_wall_has_coordinates#
Message: a `shares`'d wall also gives its own `x=`/`y=`/`thickness=`
Help: a `shares`'d wall's position and thickness are both derived from the named wall, never independently stated (final consolidation §3.1; thickness per 2026-10-25-wall-thickness-683.md §3) — remove `x=`/`y=`/`thickness=`, or remove `shares`
ww::plan::span_self_reference#
Message: `between=` names the same anchor twice
Help: `between=<AnchorA> <AnchorB>` needs two distinct anchors
ww::plan::standard_out_of_range#
Message: `standard` value for `{name}` is outside `{min}..{max}`
ww::plan::unknown_design#
Message: `{design}` names no top-level assembly in scope
Help: a `place`/`fill`/`needs design=` names a top-level assembly of this file or an imported one
ww::plan::unknown_ref#
Message: `{name}` names nothing in this plan
Help: {available}
Stage preset#
ww::preset::derived#
Reported by the compiler with a message built at run time.
ww::preset::duplicate#
Message: preset `{name}` is declared more than once in this project
Help: two presets may not share a name; rename one of them
ww::preset::range#
Reported by the compiler with a message built at run time.
ww::preset::step#
Reported by the compiler with a message built at run time.
ww::preset::type#
Reported by the compiler with a message built at run time.
ww::preset::unknown#
Reported by the compiler with a message built at run time.