This page is generated from
docs/error-codes.md— edit it there.
ArchLang error codes
Every diagnostic carries a stable code. Look one up with arch explain <CODE> (e.g. arch explain E_ROOM_SIZE). Errors abort rendering; warnings do not.
89 errors · 45 warnings
| Code | Severity | Summary |
|---|---|---|
E_ACC_PLACEMENT | error | accTitle/accDescr used outside the plan level. |
E_ARC_RADIUS | error | Arc radius too small for its chord. |
E_ARGCOUNT | error | Component called with the wrong number of arguments. |
E_ARITY | error | Built-in function called with the wrong number of arguments. |
E_ASSIGN_UNDEF | error | Assignment to an undeclared name. |
E_ATTACH_POS_RANGE | error | Opening attachment position is out of range. |
E_ATTACH_WALL_REF | error | Opening attached to an unknown or ambiguous wall. |
E_CALL_DEPTH | error | Value-function call stack too deep. |
E_COLUMN_SIZE | error | Column must have a positive size. |
E_DIM_CURVE_REF | error | Invalid dim radius/dim diameter reference. |
E_DIV_ZERO | error | Division or modulo by zero. |
E_DOMAIN | error | Math domain error. |
E_DOOR_KIND_CLAUSE | error | That clause is not available on this kind of door. |
E_DOOR_KIND_CURVED | error | A non-hinged door kind cannot sit on a curved wall. |
E_DOOR_OPEN_RANGE | error | open must be between 0 and 1. |
E_DOOR_WIDTH | error | Door must have a positive width. |
E_DOTTED_DECL | error | A dotted name cannot be declared. |
E_DUP_ID | error | Duplicate element id. |
E_DUP_INSTANCE | error | Duplicate place … as <name> instance name. |
E_FENCE_CURVED | error | A fence cannot have a curved (arc) edge. |
E_FURN_AGAINST | error | Invalid against wall fixture placement. |
E_FURN_FLUSH | error | flush on a placement that touches no edge. |
E_FURN_ROOM | error | Furniture placed in an unknown room. |
E_FURN_ROTATE | error | Furniture rotation must be a quarter-turn. |
E_FURN_SIZE | error | Furniture must have a positive size. |
E_IMPORT_BAD_SPEC | error | Malformed import spec. |
E_IMPORT_CONFLICT | error | Imported name conflicts with an existing component. |
E_IMPORT_CYCLE | error | Cyclic import. |
E_IMPORT_NOT_EXPORTED | error | Imported name is not exported by the module. |
E_IMPORT_NOT_FOUND | error | Import path could not be resolved. |
E_IMPORT_PARSE | error | Imported module has a parse error. |
E_INDEX | error | Array index out of range. |
E_INTENT_NO_DOOR | error | The plan has no modeled entrance, so reachable cannot hold. |
E_INTENT_NO_SITE | error | An intent asserts a SYMBOLIC window facing against a plan with no site. |
E_INTENT_NO_WINDOW | error | A room the brief wants a window in has too few. |
E_INTENT_NOT_ADJACENT | error | Two rooms the brief wants adjacent share no interior door. |
E_INTENT_ROOM_AREA | error | A named room's floor area is outside the brief's band. |
E_INTENT_ROOM_COUNT | error | The plan's room count does not match the brief. |
E_INTENT_ROOM_MISSING | error | A room the brief names is absent from the plan. |
E_INTENT_TOTAL_AREA | error | The plan's total floor area is outside the brief's band. |
E_INTENT_UNREACHABLE | error | A room cannot be reached from the entrance through modeled doors. |
E_JSON_KIND | error | Unknown element kind in plan JSON. |
E_JSON_SCHEMA | error | Plan JSON does not match the schema. |
E_LAYOUT_CYCLE | error | Relational room placement forms a cycle. |
E_LAYOUT_REF | error | Relational placement references an unknown room. |
E_LEVEL_DUP | error | Two level blocks declare the same storey number. |
E_LEVEL_MIX | error | A drawable statement sits beside level blocks. |
E_LEVEL_NEST | error | level used inside a block or component. |
E_OPENING_WIDTH | error | Opening must have a positive width. |
E_OUTDOOR_POLY_DEGENERATE | error | An outdoor ring is degenerate, or a balcony was given one. |
E_OUTDOOR_POLY_SELF_INTERSECT | error | An outdoor ring crosses itself. |
E_OUTDOOR_RAIL | error | A rail clause on something that is not a balcony, or an unknown edge word. |
E_OUTDOOR_SIZE | error | An outdoor surface must have a positive size. |
E_PARSE | error | The source could not be read: its SHAPE is wrong. |
E_PLACE_POLY | error | A rectangle-only placement clause aimed at a polygon room. |
E_PLACE_REF | error | Furniture placed in an unknown or non-absolute room. |
E_PNG_DEPENDENCY | error | PNG/PDF export needs an optional dependency that is not installed. |
E_RANGE_LIMIT | error | Range too large. |
E_RECURSION | error | Component recursion too deep. |
E_REDEF | error | Name already defined in this scope. |
E_ROOF_AMBIGUOUS | error | roof overhang cannot tell which wall ring to follow. |
E_ROOF_CURVED | error | roof overhang on a wall with a curved edge. |
E_ROOF_OVERHANG | error | roof overhang is zero or negative. |
E_ROOF_PLACEMENT | error | roof used inside a component body. |
E_ROOF_POLY_DEGENERATE | error | roof polygon outline has fewer than 3 effective vertices. |
E_ROOF_SELF_INTERSECT | error | The roof outline crosses itself. |
E_ROOF_WALL | error | roof overhang … wall <id> names a wall that cannot carry a roof. |
E_ROOM_ALIGN | error | Unknown relational alignment edge. |
E_ROOM_ALIGN_AXIS | error | Relational alignment edge belongs to the other axis. |
E_ROOM_POLY_DEGENERATE | error | Polygon room has fewer than three effective vertices. |
E_ROOM_POLY_SELF_INTERSECT | error | Polygon room intersects itself. |
E_ROOM_RADIUS | error | Circular room needs a positive radius. |
E_ROOM_SIZE | error | Room must have a positive size. |
E_SITE_BOUNDARY_DEGENERATE | error | The site boundary encloses no lot. |
E_SITE_BOUNDARY_SELF_INTERSECT | error | The site boundary crosses itself. |
E_SITE_DUP | error | Two site blocks in one plan. |
E_SITE_NO_STREET | error | A site block declares no street. |
E_STAIR_WIDTH | error | Stair flight width is outside the footprint. |
E_STRIP_NEST | error | Illegal strip nesting. |
E_STRIP_SIZE | error | Room in a strip is missing a size. |
E_TYPE | error | Type mismatch. |
E_UNKNOWN_COMPONENT | error | Unknown component. |
E_UNKNOWN_FN | error | Unknown function. |
E_UNKNOWN_REF | error | Unknown reference. |
E_VERT_SIZE | error | Vertical circulation must have a positive size. |
E_VOID_SIZE | error | A floor void must have a positive size. |
E_WALL_THICKNESS | error | Wall must have a positive thickness. |
E_WHILE_LIMIT | error | while exceeded its iteration cap. |
E_WINDOW_WIDTH | error | Window must have a positive width. |
W_ALIAS_MATCH | warning | A room's use was inferred from an indirect alias, not stated. |
W_BALCONY_NO_DOOR | warning | A balcony with no way onto it. |
W_BATH_VIA_BEDROOM | warning | Bathroom is reachable only through a bedroom. |
W_BEDROOM_NO_WINDOW | warning | Bedroom has no window. |
W_CIRCUITOUS_PATH | warning | A room is reached by a very roundabout path. |
W_DIM_INSIDE | warning | A hand-written dimension line lands inside the building. |
W_DIM_NO_WALL | warning | A dim faces/dim clear endpoint has no wall to measure to. |
W_DIM_OVERLAP | warning | Two hand-written dimensions are drawn on top of each other. |
W_DOOR_CLEARANCE | warning | Door is narrower than the minimum clear width. |
W_DOOR_OFF_WALL | warning | Door does not lie on any wall. |
W_DOORWAY_BLOCKED | warning | A doorway's landing is blocked. |
W_DUP_ACC_METADATA | warning | Duplicate accTitle/accDescr. |
W_EMPTY_PLAN | warning | Empty plan. |
W_FIXTURE_BACK_TO_ROOM | warning | A fixture stands against a wall but faces the wrong way. |
W_FIXTURE_FLOATING | warning | A plumbing/kitchen fixture is not against a wall. |
W_FIXTURE_WRONG_ROOM | warning | Fixture is not inside its declared room. |
W_FURN_CLEARANCE | warning | A fixture's use-space is blocked. |
W_FURNITURE_OVERLAP | warning | Two pieces of furniture overlap. |
W_FURNITURE_WALL_COLLISION | warning | Furniture penetrates a wall. |
W_GARAGE_TOO_NARROW | warning | A garage is too narrow to park in. |
W_HATCH_SCALE | warning | Hatch scale must be positive; using 1. |
W_IMPORT_EMPTY_FILE | warning | Whole-file import binds an empty component. |
W_NO_ENTRANCE | warning | The plan has no exterior door. |
W_OPENING_OFF_WALL | warning | Opening does not lie on any wall. |
W_OUTDOOR_OVERLAPS_ROOM | warning | A ground surface is laid over a room's floor. |
W_PATH_TOO_NARROW | warning | The walk to a room squeezes below a passable width. |
W_POCKET_RUN | warning | A pocket door has no wall to slide into. |
W_ROOM_DISCONNECTED | warning | Room has no door — it can't be entered. |
W_ROOM_LABEL_OUTSIDE | warning | A room's explicit label anchor falls outside the room. |
W_ROOM_NO_CLEAR_PATH | warning | A room cannot be entered or crossed. |
W_ROOM_NO_FIXTURE | warning | Bathroom or kitchen has no fixtures. |
W_ROOM_NOT_ENCLOSED | warning | Bathroom is not fully enclosed. |
W_ROOM_NOT_EQUATOR_FACING | warning | A habitable room has windows, but none faces the equator side. |
W_ROOM_OVERLAP | warning | Rooms overlap. |
W_ROOM_TOO_SMALL | warning | Room is implausibly small. |
W_ROOM_UNREACHABLE | warning | Room cannot be reached from the entrance. |
W_SANITIZED_CONFIG | warning | A disallowed config value was stripped. |
W_SCALE_OVERFLOW | warning | The drawing does not fit the declared paper at the declared scale. |
W_STAIR_UNMATCHED | warning | A run of vertical circulation appears on only one storey. |
W_SWING_OBSTRUCTED | warning | Door swing is obstructed. |
W_SWING_ROOM_NOT_ADJACENT | warning | swing into <room> names a room the door does not border. |
W_UNKNOWN_MATERIAL | warning | Unknown wall material; using the default hatch. |
W_UNKNOWN_STYLE_KEY | warning | Unknown style key. |
W_UNKNOWN_THEME_KEY | warning | Unknown theme key. |
W_WINDOW_OFF_WALL | warning | Window does not lie on any wall. |
E_ACC_PLACEMENT
error — accTitle/accDescr used outside the plan level.
Cause. An accTitle or accDescr accessibility-metadata statement appeared inside a component or a control-flow block. They describe the whole plan, so they are only legal as direct plan-level statements.
Fix. Move the accTitle/accDescr line up to the plan body, alongside units/north.
component c() { accDescr "x" } # error: only allowed at plan levelE_ARC_RADIUS
error — Arc radius too small for its chord.
Cause. An arc (x,y) radius R edge asks for a circle of radius R through the previous vertex and this one, but R is less than half the straight-line distance between them (or is not positive) — no such circle exists.
Fix. Raise the radius to at least half the chord (the message states the minimum), or move the endpoints closer together. arch fix applies the minimum for you.
wall exterior thickness 200 { (0,0) arc (10000,0) radius 3000 } # error: needs R >= 5000E_ARGCOUNT
error — Component called with the wrong number of arguments.
Cause. A component instance supplies more or fewer arguments than the component declares parameters.
Fix. Pass exactly one argument per declared parameter.
component bed(x, y) { … }
bed(300) # error: expects 2 argumentsE_ARITY
error — Built-in function called with the wrong number of arguments.
Cause. A built-in (e.g. abs, sqrt, len) was called with the wrong argument count.
Fix. Check the function's arity; most built-ins take one argument.
let x = abs(1, 2) # error: abs expects 1 argumentE_ASSIGN_UNDEF
error — Assignment to an undeclared name.
Cause. NAME = value was used for a name never introduced with let.
Fix. Declare it first with let, or fix a typo in the name.
x = 5 # error: declare with `let x = …` firstE_ATTACH_POS_RANGE
error — Opening attachment position is out of range.
Cause. The at <pos> of an attached opening is outside the host wall: a percentage outside 0–100%, a millimetre distance outside 0 … wall length, or — since the position may be an expression — a value that is not a finite number at all.
Fix. Use a percentage in 0–100%, a millimetre distance within the wall's run, or center. The non-finite case carries no fix: there is no nearest legal value to clamp to, so check the expression that produced it.
door on w1 at 150% width 900 # error: 150% is past the wall endE_ATTACH_WALL_REF
error — Opening attached to an unknown or ambiguous wall.
Cause. A door/window/opening … on <wall> at <pos> names a wall id (or category) that no wall has, or one that matches more than one wall — so the compiler cannot pick the polyline to walk.
Fix. Reference an existing, unique wall id (add id= to the wall if needed).
door on w1 at 40% width 900 # error if no wall id=w1 (or several match)E_CALL_DEPTH
error — Value-function call stack too deep.
Cause. A value-function recurses (directly or mutually) beyond the call-depth limit.
Fix. Make the recursion terminate, or rewrite it iteratively with a bounded while.
let f(n) = f(n + 1) # error: never terminatesE_COLUMN_SIZE
error — Column must have a positive size.
Cause. A column's width or height evaluated to zero or a negative number.
Fix. Give the column a positive size W x H.
column at (0,0) size 0x300 # error: width is 0E_DIM_CURVE_REF
error — Invalid dim radius/dim diameter reference.
Cause. A curve call-out references an element that does not exist, is not the right shape (a diameter on a rectangular room, a radius on a wall with no arc edge), matches several walls, or omits segment <n> on a wall with more than one arc. The compiler will not guess which curve was meant.
Fix. Name an existing, unique wall id whose edge is an arc (adding segment <n> when it has several), or an existing room circle id for diameter.
dim radius w1 # error if w1 is straight, unknown, or has two arc edgesE_DIV_ZERO
error — Division or modulo by zero.
Cause. An expression divides (or takes a remainder) by a value that evaluates to zero.
Fix. Guard the divisor, or use a non-zero value.
let x = 10 / 0 # errorE_DOMAIN
error — Math domain error.
Cause. A built-in received an out-of-domain argument (e.g. sqrt of a negative number).
Fix. Pass a value within the function's domain.
let x = sqrt(-1) # errorE_DOOR_KIND_CLAUSE
error — That clause is not available on this kind of door.
Cause. A door statement carries a clause its kind has no meaning for: hinge on any of the sliding family (sliding/barn/bifold/pocket — nothing is hinged to a jamb), swing on a sliding or pocket door (the panel stays in the plane of the wall, or inside it), or slide/open on a hinged door (nothing travels along the wall). ArchLang refuses rather than draws the statement as if the clause were absent — silently ignoring a written clause is the silent-error design this project rules out (the v1.23 precedent: rectangle-only clauses REFUSE a polygon room rather than approximate it).
Fix. Delete the clause (the machine-applicable fix does exactly that), or change the door's kind to one the clause belongs to. swing on a barn or bifold door is legal and means which FACE of the wall the panel hangs on or folds toward — it is not a leaf arc.
door pocket on w1 at 50% width 900 hinge left # error: a pocket door has no hingeE_DOOR_KIND_CURVED
error — A non-hinged door kind cannot sit on a curved wall.
Cause. The panel of a sliding, barn, bifold or pocket door is a straight rectangle running along a straight track, and its pocket/track geometry is straight by construction — none of that survives on a wall whose hosting edge is an arc. A hinged leaf does survive (its swing is taken from the tangent at the doorway), so only the sliding family is refused. Refusing is deliberate: drawing a straight panel across a curved reveal would be a wrong drawing with no diagnostic.
Fix. Use a hinged door on the curve (the default — delete the kind word), or move the door onto one of the wall's straight runs.
wall w1 thickness 200 { (0,0) arc (6000,0) radius 4000 }
door pocket on w1 at 50% width 900 # error: curved hostE_DOOR_OPEN_RANGE
error — open must be between 0 and 1.
Cause. open <f> is the fraction of its travel a sliding-family panel is DRAWN at — 0 is closed, 1 fully open — so a value outside [0,1] names a position the panel cannot reach. It is a drawing fact only: nothing measured (lint, describe, the intent channel) reads it, so a half-open door can never silence a clearance warning.
Fix. Give open a fraction in [0,1]; arch fix clamps it to the nearer end for you. Omit it entirely for the default 0.5.
door sliding on w1 at 50% width 1200 open 1.5 # error: outside [0,1]E_DOOR_WIDTH
error — Door must have a positive width.
Cause. A door's width evaluated to zero or a negative number.
Fix. Give the door a positive width.
door at (0,0) width 0 # errorE_DOTTED_DECL
error — A dotted name cannot be declared.
Cause. A dotted name like west.main addresses an element INSIDE a placed instance. The namespace belongs to the place, so a dotted name is only ever a reference — it can never be declared with id=, let, as, or for.
Fix. Declare the short name and address it from outside as <instance>.<name>.
room id=main at (0,0) size 3000x3000 # then, in the plan: furniture bed in west.main centeredE_DUP_ID
error — Duplicate element id.
Cause. Two elements declare the same id=…; ids must be unique across the plan.
Fix. Rename one of them, or drop the explicit id to auto-generate a unique one.
room id=a at (0,0) size 1x1
room id=a at (1,0) size 1x1 # error: duplicate id "a"E_DUP_INSTANCE
error — Duplicate place … as <name> instance name.
Cause. Two place statements claim the same instance name. The name is the id NAMESPACE for everything inside the instance, so reusing it would silently merge two instances' ids.
Fix. Give each instance its own name (as west / as east).
place wing() as west at (0,0)
place wing() as west at (9000,0) # error: instance "west" already usedE_FENCE_CURVED
error — A fence cannot have a curved (arc) edge.
Cause. An arc … radius … clause appeared inside a fence { … } body. The post pitch, the panel offset and the reported length_mm are all measured along a STRAIGHT run, so a faceted curve would silently measure the facets rather than the arc — this release refuses rather than approximating (the same decision roof makes with E_ROOF_CURVED).
Fix. Approximate the curve with short straight runs, which is what a fence built on a curve actually is.
fence picket { (0,0) arc (3000,3000) radius 3000 } # error: curved edgeE_FURN_AGAINST
error — Invalid against wall fixture placement.
Cause. A wall-anchored fixture references an unknown wall, omits segment on a multi-segment wall, omits side, sits on a non-axis-aligned segment, has an out-of-range offset, or also sets rotate. The compiler will not guess which wall/side/segment was meant.
Fix. Name an existing wall id, add segment <n> for multi-segment walls, give side left|right, keep the segment axis-aligned, and drop any explicit rotate.
furniture wc against wall w1 side left size 400x700 # error if w1 is unknown or multi-segmentE_FURN_FLUSH
error — flush on a placement that touches no edge.
Cause. flush measures inset from the inner face of the wall behind an anchored edge. A centered piece (or the equivalent anchor center) is pushed against no edge, so there is no wall face to measure from.
Fix. Anchor the piece to the edge you want it flush with (anchor bottom flush, anchor top-left flush), or drop flush and keep it centred.
furniture wc in bath centered flush size 400x700 # error: centred, so nothing to be flush withE_FURN_ROOM
error — Furniture placed in an unknown room.
Cause. A furniture item names a room with in <roomId>, but no room has that id.
Fix. Use the id of an existing room id=…, or drop the in clause.
furniture bed at (0,0) size 1500x2000 in bedrm # error: no room id=bedrmE_FURN_ROTATE
error — Furniture rotation must be a quarter-turn.
Cause. A furniture item's rotate is not one of 0, 90, 180, or 270 degrees.
Fix. Use a quarter-turn: rotate 0|90|180|270.
furniture wc at (0,0) size 400x700 rotate 45 # error: not a quarter-turnE_FURN_SIZE
error — Furniture must have a positive size.
Cause. A furniture item's width or height evaluated to zero or a negative number.
Fix. Give the item a positive size W x H.
furniture bed at (0,0) size 0x2000 # errorE_IMPORT_BAD_SPEC
error — Malformed import spec.
Cause. The string after import is not a recognizable module reference.
Fix. Use a relative path ("lib/x.arch") or a namespaced spec ("@scope/name:1.0.0").
import "???" : a # errorE_IMPORT_CONFLICT
error — Imported name conflicts with an existing component.
Cause. An imported component has the same name as one already defined or imported.
Fix. Rename with as, or remove the duplicate.
import "lib.arch": bed as lib_bedE_IMPORT_CYCLE
error — Cyclic import.
Cause. Modules import each other in a cycle, which cannot be resolved.
Fix. Break the cycle so module dependencies form a tree.
# a.arch imports b.arch which imports a.arch → errorE_IMPORT_NOT_EXPORTED
error — Imported name is not exported by the module.
Cause. The module has no component with the requested name.
Fix. Import a name the module actually defines (check its components).
import "lib.arch": nope # error if lib.arch has no `component nope`E_IMPORT_NOT_FOUND
error — Import path could not be resolved.
Cause. The World could not read the module at the given path.
Fix. Check the path (relative to the importing file) and that the file exists.
import "lib/missing.arch": a # errorE_IMPORT_PARSE
error — Imported module has a parse error.
Cause. The module referenced by import does not itself parse.
Fix. Fix the syntax error in the imported module.
# error originates in the imported fileE_INDEX
error — Array index out of range.
Cause. arr[i] used an index outside 0 .. len(arr) - 1.
Fix. Clamp or check the index against len(arr).
let a = [1, 2]
let x = a[5] # errorE_INTENT_NO_DOOR
error — The plan has no modeled entrance, so reachable cannot hold.
Cause. An intent asserts reachable: true, but the plan has no door connecting a room to the exterior — nothing is enterable, so no room is reachable.
Fix. Add an exterior entrance door on a perimeter wall. Advisory tier: reported and scored by validateIntent but does NOT fail ok (gate: false).
door on exterior at 50% width 900 # a front doorE_INTENT_NO_SITE
error — An intent asserts a SYMBOLIC window facing against a plan with no site.
Cause. An intent roomsInclude[].windows.facing names one of the derived directions (street, back, equator_side, sunrise_side, sunset_side) but the plan declares no site block, so there is nothing to resolve the name against. The question is unanswerable, not answered no.
Fix. Declare site { street … } in the plan (that is what gives the derived names their letters), or assert a plain compass letter instead. Gating tier: this failure fails validateIntent's ok — it is a refusal, never a silent pass and never a silent miss.
plan "H" {
units mm
site { street south } # now `facing: "equator_side"` resolves to "S"
}E_INTENT_NO_WINDOW
error — A room the brief wants a window in has too few.
Cause. An intent roomsInclude[].windows requires at least one window in a concept's room(s) (e.g. "give the bedroom a window"), but the plan places fewer than the required count.
Fix. Add a window on one of that room's walls. Gating tier: this failure DOES fail validateIntent's ok.
window on north at 40% width 1200 # light the bedroomE_INTENT_NOT_ADJACENT
error — Two rooms the brief wants adjacent share no interior door.
Cause. An intent adjacency edge names two concepts (e.g. hall ↔ bathroom) that are not joined by an interior door or cased opening in the plan's modeled connectivity.
Fix. Add a door (or opening) on the wall the two rooms share so they are directly connected. Advisory tier: this is scored and reported by validateIntent but does NOT fail ok (gate: false) — one-shot topology is what the loop tools address.
door on wall_hall_bath width 800 # connect the hall to the bathroomE_INTENT_ROOM_AREA
error — A named room's floor area is outside the brief's band.
Cause. An intent roomsInclude[].areaM2 gives a per-room area band (from a number in the brief, ±10% for "about N"), but the matched room's area falls outside it.
Fix. Resize the room so its floor area lands in the band. Gating tier: this failure fails validateIntent's ok. Assert a band only where the brief states a number — qualitative size words license none.
room at (0,0) size 4000x3000 label "Bedroom" # 12 m²E_INTENT_ROOM_COUNT
error — The plan's room count does not match the brief.
Cause. An intent rooms count (asserted only when the brief ENUMERATES its rooms) does not match the plan's room total. A single surplus room passes only when it is pure circulation (a hall/corridor) — policy B.
Fix. Add or remove rooms to reach the enumerated count. Gating tier: this failure fails validateIntent's ok.
# brief lists 4 rooms; the plan draws 5 (and the extra is a bedroom, not a hall)E_INTENT_ROOM_MISSING
error — A room the brief names is absent from the plan.
Cause. An intent roomsInclude[] concept (e.g. "bathroom") matched no room by label, room_type, or uses — the plan is missing a room the brief asked for.
Fix. Add a room whose label, uses, or type matches the concept. Gating tier: this failure fails validateIntent's ok.
room at (0,0) size 2000x2000 label "Bathroom" uses bath # supply the missing roomE_INTENT_TOTAL_AREA
error — The plan's total floor area is outside the brief's band.
Cause. An intent totalAreaM2 band (from a number in the brief, ±10% for "about N") does not contain the plan's total floor area.
Fix. Grow or shrink rooms so the total lands in the band. Gating tier: this failure fails validateIntent's ok. Assert a band only where the brief states a number.
# brief says "about 42 m²" (band 37.8–46.2); the plan totals 52 m²E_INTENT_UNREACHABLE
error — A room cannot be reached from the entrance through modeled doors.
Cause. An intent asserts reachable: true and the plan HAS an entrance, but one or more rooms are cut off — no chain of modeled doors reaches them from the exterior.
Fix. Add interior doors so every room connects back to the entrance. Advisory tier: reported and scored by validateIntent but does NOT fail ok (gate: false).
door on wall_hall_store width 800 # connect the isolated roomE_JSON_KIND
error — Unknown element kind in plan JSON.
Cause. An element in the JSON names a kind (or lives in an array) the builder does not recognize — e.g. an opening whose kind is not door, window, or opening.
Fix. Use one of the supported kinds: opening kind must be door | window | opening.
{ "openings": [ { "kind": "portal", "width": 900 } ] } # error at /openings/0/kind: unknown kind "portal"E_JSON_SCHEMA
error — Plan JSON does not match the schema.
Cause. A value passed to planFromJson has the wrong shape or type for its JSON path (e.g. a room missing a numeric width, a non-array rooms), or it uses a construct the JSON form cannot represent — scripting (let/for/if/component) and import are intentionally not supported.
Fix. Fix the value at the reported JSON path (the message names it, e.g. /rooms/0/width); express geometry as concrete numbers, and author scripting/imports in .arch source instead.
{ "rooms": [ { "x": 0, "y": 0, "width": "big", "height": 3000 } ] } # error at /rooms/0/width: expected a numberE_LAYOUT_CYCLE
error — Relational room placement forms a cycle.
Cause. Rooms placed with right-of/below/… reference each other in a loop, so no order resolves them.
Fix. Break the cycle by giving one of the rooms absolute at (x,y) coordinates.
room id=a right-of b size 100x100
room id=b left-of a size 100x100 # error: a ↔ b cycleE_LAYOUT_REF
error — Relational placement references an unknown room.
Cause. A right-of/below/… clause names a room id that does not exist in the plan.
Fix. Reference an existing room id, or fix the typo.
room id=k right-of ghost size 100x100 # error: no room "ghost"E_LEVEL_DUP
error — Two level blocks declare the same storey number.
Cause. Level numbers identify the storeys of one building, so each may be declared once; two level 1 blocks would produce two pages both claiming to be level 1.
Fix. Renumber one of them, or merge the two bodies into a single level block.
level 1 { room at (0,0) size 3000x3000 }
level 1 { room at (0,0) size 3000x3000 } # error: level 1 twiceE_LEVEL_MIX
error — A drawable statement sits beside level blocks.
Cause. A plan is either single-storey (no level block) or entirely made of them: anything that draws belongs to exactly one storey, so a room/wall/door/for/strip/component call at plan level next to a level block has no storey to belong to.
Fix. Move the statement inside the level block it belongs to. Only settings (units/grid/paper/scale/north/site/dims/title/axes/schedule/legend), component/import declarations, and the plan-global let/set stay outside — they apply to every level.
plan "H" {
room at (0,0) size 3000x3000 # error: move it into a level
level 1 { wall exterior thickness 200 { (0,0) (3000,0) close } }
}E_LEVEL_NEST
error — level used inside a block or component.
Cause. A level block is a plan-level statement: it partitions the whole plan into storeys, so it cannot be nested inside another level, a for/if/while body, a strip, or a component definition.
Fix. Move the level block out to the plan body. To draw the same content on several storeys, put it in a component and call it from each level.
component c() { level 1 { } } # error: only allowed at plan levelE_OPENING_WIDTH
error — Opening must have a positive width.
Cause. A cased opening's width evaluated to zero or a negative number.
Fix. Give the opening a positive width.
opening at (0,0) width 0 # errorE_OUTDOOR_POLY_DEGENERATE
error — An outdoor ring is degenerate, or a balcony was given one.
Cause. Either an outdoor … polygon … ring has fewer than 3 effective vertices once duplicate and collinear points are removed (so it encloses no area), or the ring was written on a balcony, which is rectangle-only: a balcony's railing is derived per EDGE — top, bottom, left, right — and a ring has no such edges.
Fix. Give the ring at least 3 corners that are not all on one line. For a balcony, use at (x,y) size WxH; a polygonal balcony is deferred by name, not supported.
outdoor paving polygon (0,0) (1000,0) (2000,0) # error: all three are collinearE_OUTDOOR_POLY_SELF_INTERSECT
error — An outdoor ring crosses itself.
Cause. The vertices of an outdoor … polygon … describe a ring whose edges intersect (a bow-tie), so it encloses no single area — there is no unambiguous surface to hatch or to measure. Usually two vertices in the wrong order.
Fix. Reorder the vertices so the ring is a simple polygon, walking the outline once without crossing back over itself.
outdoor deck polygon (0,0) (4000,4000) (4000,0) (0,4000) # error: a bow-tieE_OUTDOOR_RAIL
error — A rail clause on something that is not a balcony, or an unknown edge word.
Cause. rail names which edges carry a railing, and only a balcony has one. Written on any other ground surface it has no meaning — and a clause with no meaning is refused rather than silently dropped, so a plan never draws differently from what it says. The same code covers an edge word outside top|bottom|left|right|all|none.
Fix. Delete the clause, or make the surface an outdoor balcony. For an unknown word, use one of the six edge words.
outdoor deck at (0,0) size 3000x2000 rail all # error: a deck has no railingE_OUTDOOR_SIZE
error — An outdoor surface must have a positive size.
Cause. An outdoor … at (x,y) size WxH statement's width or height evaluated to zero or a negative number, so there is no ground to draw, hatch or measure.
Fix. Give it a positive size W x H — the surface's extent in plan. For a shape that is not a rectangle, use the polygon spelling instead.
outdoor lawn at (0,0) size 0x4000 # error: zero widthE_PARSE
error — The source could not be read: its SHAPE is wrong.
Cause. The lexer or the parser could not make a statement out of the bytes at this span — a missing or misspelled keyword, a value where a keyword belongs, an unterminated string, an unbalanced brace, clauses written in the wrong order. It is the one code that says nothing about what the plan MEANS: resolution never ran here, so no measurement, no geometry and no soundness rule had a chance to speak.
Fix. Read the message: it names what was expected and what was found, at a byte span. Compare the statement against arch spec's one line for that keyword — clause ORDER is part of the grammar, not a suggestion. Unlike every other code in this catalog, there is no machine-applicable fix to apply, because the compiler has no reading of the text to correct.
door on w1 at 40% width 900 wall w1 # error: `wall` pairs with the `at (x,y)` form onlyE_PLACE_POLY
error — A rectangle-only placement clause aimed at a polygon room.
Cause. Relational room placement (right-of/left-of/below/above) and room-relative furniture placement (in <room> centered|anchor …) are closed-form arithmetic on a room's four RECTANGLE edges. A room polygon has no such edges, and its bounding box is not its floor — an anchor could land the piece in a notch that is outside the room — so the compiler refuses instead of guessing (ADR 0005).
Fix. Place the room or the fixture with explicit at (x,y) coordinates (a fixture may add rotate), or make the referenced room rectangular.
room id=L polygon (0,0) (6000,0) (6000,4000) (3000,4000) (3000,6000) (0,6000)
furniture wc in L anchor bottom-left # error: L is a polygon roomE_PLACE_REF
error — Furniture placed in an unknown or non-absolute room.
Cause. A furniture … in <room> centered|anchor … names a room that does not exist, or one positioned relationally (right-of/…) whose box is not yet fixed when the fixture is placed.
Fix. Reference an existing room given absolute at (x,y) coordinates.
furniture bed in bedrm centered size 1500x2000 # error: no room id=bedrmE_PNG_DEPENDENCY
error — PNG/PDF export needs an optional dependency that is not installed.
Cause. Rendering to PNG needs @resvg/resvg-js (PDF needs pdfkit); the optional binary is absent in this environment (it is not bundled, to keep the core zero-dependency).
Fix. Install the optional dependency (npm install @resvg/resvg-js), or re-run with --install to fetch it automatically, or render to SVG/DXF (zero-dependency).
arch preview plan.arch --install # fetches @resvg/resvg-js, then renders the PNGE_RANGE_LIMIT
error — Range too large.
Cause. A lo..hi range would expand to more elements than the safety cap allows.
Fix. Use a smaller range, or restructure to avoid materializing it.
for i in 0..1000000 { … } # error: range too largeE_RECURSION
error — Component recursion too deep.
Cause. Component instantiation nested beyond the depth limit (usually unbounded self-instantiation).
Fix. Add a base case so the recursion terminates.
component r(n) { r(n) } # error: never terminatesE_REDEF
error — Name already defined in this scope.
Cause. A let re-declares a name already bound in the same scope.
Fix. Rename one binding, or use NAME = … to reassign instead of redeclaring.
let x = 1
let x = 2 # error: redefinitionE_ROOF_AMBIGUOUS
error — roof overhang cannot tell which wall ring to follow.
Cause. The overhang sugar offsets ONE closed wall ring, and with no wall <id> clause it infers that ring as the plan's single closed exterior wall. The plan has none, or has more than one, so there is nothing to infer — and picking the first would silently draw a roof over part of the building.
Fix. Name the ring (roof overhang 600 wall <id>), or state the outline yourself with roof polygon (x,y) (x,y) (x,y) ….
plan "H" {
units mm
room id=r1 at (0,0) size 4000x3000
roof overhang 600 # error: no closed exterior wall to follow
}E_ROOF_CURVED
error — roof overhang on a wall with a curved edge.
Cause. The named ring has an arc edge. Offsetting a curve is a different construction from mitring two straight faces (concentric radii, plus the cases where the offset radius passes through zero), and faceting it would put a tessellation in the one place a reader is entitled to read a true parallel.
Fix. State the outline explicitly with roof polygon …, or follow a straight-edged wall ring instead.
wall id=drum exterior thickness 200 { (0,0) arc (6000,0) radius 4000 (6000,4000) (0,4000) close }
roof overhang 600 wall drum # error: arc edgeE_ROOF_OVERHANG
error — roof overhang is zero or negative.
Cause. An overhang is a distance the roof projects PAST the wall's outer face, so it must be positive. Zero would draw the outline on the wall face (say nothing instead), and a negative value would draw it inside the building.
Fix. Give a positive projection in mm, e.g. roof overhang 600.
roof overhang 0 # error: must be positiveE_ROOF_PLACEMENT
error — roof used inside a component body.
Cause. A roof belongs to a building, not to a reusable part of one: roof overhang is offset from the plan's closed exterior wall ring, and a component is authored in its own local frame with no such ring. Two placed copies would each derive an outline and the plan would draw two roofs.
Fix. Move the roof line out to the plan body (or into the level block it belongs to).
component wing() { roof overhang 600 } # error: only allowed at plan levelE_ROOF_POLY_DEGENERATE
error — roof polygon outline has fewer than 3 effective vertices.
Cause. After removing duplicate and straight-through (collinear) points the ring encloses no area, so it is a line or a point rather than a roof outline.
Fix. Give at least three vertices that actually turn a corner.
roof polygon (0,0) (4000,0) (8000,0) # error: all three are collinearE_ROOF_SELF_INTERSECT
error — The roof outline crosses itself.
Cause. Either the roof polygon ring was written as a bow-tie, or the derived overhang offset is wide enough to swallow a notch in the wall it follows (a 900 mm eave across a 600 mm light well) and the pushed-out faces cross. Neither encloses a single area.
Fix. Reorder the vertices, or reduce the overhang — or state the outline explicitly with roof polygon ….
roof polygon (0,0) (4000,4000) (4000,0) (0,4000) # error: bow-tieE_ROOF_WALL
error — roof overhang … wall <id> names a wall that cannot carry a roof.
Cause. The named wall is not declared in this plan, or it is not a closed ring. An overhang is offset from a loop; an open polyline has no inside to be outside of.
Fix. Check the id, and give the wall a close so its points form a ring.
wall id=w1 exterior thickness 200 { (0,0) (8000,0) }
roof overhang 600 wall w1 # error: not a closed ringE_ROOM_ALIGN
error — Unknown relational alignment edge.
Cause. A relationally-placed room's align <word> names something that is not an alignment edge. The set is closed (top, middle, bottom for right-of/left-of; left, center, right for below/above), and an unrecognised word used to fall through to the leading edge silently — drawing the plan as if align had never been written.
Fix. Use one of the six edges; the diagnostic suggests the nearest one and carries a fix that rewrites just that word.
room id=b right-of a align sideways size 3000x3000 # error: not an edge (did you mean `bottom`?)E_ROOM_ALIGN_AXIS
error — Relational alignment edge belongs to the other axis.
Cause. A relationally-placed room's align <edge> names a real edge, but not one of the axis that direction aligns on. A horizontal relation (right-of/left-of) offsets its room vertically, so it takes top|middle|bottom; a vertical relation (below/above) offsets horizontally, so it takes left|center|right. (middle and center are honoured on both — they are the same instruction spelled twice.) A cross-axis edge used to be ignored in silence, drawing the room against the leading edge exactly as if align had never been written — distinct from E_ROOM_ALIGN, where the word is not an edge at all.
Fix. Use the edge of the correct axis; the diagnostic names its exact counterpart (leading stays leading, trailing stays trailing) and carries a fix that rewrites just that word.
room id=b right-of a align right size 3000x3000 # error: `right` is horizontal (did you mean `bottom`?)E_ROOM_POLY_DEGENERATE
error — Polygon room has fewer than three effective vertices.
Cause. After removing duplicate and straight-through (collinear) points, the ring encloses no area — so it has no floor, no centroid and no containment test.
Fix. Give the room at least three vertices that actually turn a corner.
room polygon (0,0) (4000,0) (8000,0) # error: all three are collinearE_ROOM_POLY_SELF_INTERSECT
error — Polygon room intersects itself.
Cause. Two of the ring's edges cross (or run along each other), so the polygon is not simple and which side is 'inside' is undefined — area, containment and adjacency would all be meaningless.
Fix. Reorder the vertices so the ring is traced once around the room without crossing itself (a bow-tie usually means two vertices are swapped).
room polygon (0,0) (4000,4000) (4000,0) (0,4000) # error: bow-tieE_ROOM_RADIUS
error — Circular room needs a positive radius.
Cause. A room circle at (cx,cy) radius R has R of zero or less, so it encloses no floor — there is no area, no centroid and no containment test to compute.
Fix. Give the room a positive radius in millimetres.
room circle at (5000,5000) radius 0 # error: no floorE_ROOM_SIZE
error — Room must have a positive size.
Cause. A room's width or height evaluated to zero or a negative number.
Fix. Give the room a positive size W x H.
room at (0,0) size 0x4000 # error: width is 0E_SITE_BOUNDARY_DEGENERATE
error — The site boundary encloses no lot.
Cause. A site { boundary … } ring has fewer than 3 effective vertices once duplicate and collinear points are removed, so there is no lot to draw a property line round or to report an area for.
Fix. Give the boundary at least 3 corners that are not all on one line.
site { street north
boundary (0,0) (10000,0) } # error: two points is not a lotE_SITE_BOUNDARY_SELF_INTERSECT
error — The site boundary crosses itself.
Cause. The vertices of a site { boundary … } describe a ring whose edges intersect, so it encloses no single lot and describe --json's site.lot_area_m2 would have no honest value. Usually two vertices in the wrong order.
Fix. Reorder the vertices so the boundary walks the lot line once without crossing back over itself.
site { street north
boundary (0,0) (10000,10000) (10000,0) (0,10000) } # error: a bow-tieE_SITE_DUP
error — Two site blocks in one plan.
Cause. A plan declares site more than once. axes merges when repeated because two axis lists append; two street values contradict, and silently keeping the last one would hide an authoring mistake in the very statement whose job is to be the single source of orientation.
Fix. Delete one of the blocks, or merge their fields into a single site { … }. The first block is the one that takes effect.
plan "H" {
units mm
site { street south }
site { street north } # error: site already declared
}E_SITE_NO_STREET
error — A site block declares no street.
Cause. street is the only required field of site: every derived name (back, and the three _side names) is a function of it, so a site without one derives nothing at all. Refusing beats defaulting — there is no direction a building's frontage faces by default.
Fix. Add street north, south, east or west inside the block. hemisphere is the optional field (it defaults to north).
plan "H" {
units mm
site { hemisphere south } # error: no street
}E_STAIR_WIDTH
error — Stair flight width is outside the footprint.
Cause. A stair's optional width is the FLIGHT width measured across the run, so it has to be positive and no wider than the footprint's cross-axis extent (the short side — the flight always runs along the long one). This value is not.
Fix. Drop width to fill the footprint, or give a value between 0 and the footprint's short side.
stair id=s at (0,0) size 900x2600 dir up width 1200 # error: cross extent is 900E_STRIP_NEST
error — Illegal strip nesting.
Cause. A strip block appears inside a component, a control-flow block, or another strip. Strips place rooms and are only legal as direct plan-level statements.
Fix. Move the strip to the plan body, alongside the other elements.
component c() { strip right at (0,0) gap 0 { … } } # error: nested stripE_STRIP_SIZE
error — Room in a strip is missing a size.
Cause. A room inside a strip { … } gives no main-axis extent, or gives none while the strip supplies no cross-axis height/width for it to inherit — so its rectangle is undetermined.
Fix. Give the room a size <main> (main-axis extent) plus either a strip height/width or its own size <main>x<cross>.
strip right at (0,0) gap 100 { room size } # error: no extentE_TYPE
error — Type mismatch.
Cause. A value was used where another type was required (e.g. a string where a number is expected, or a non-array in for).
Fix. Convert or supply the expected type.
room at (0,0) size "big" x 10 # error: size needs numbersE_UNKNOWN_COMPONENT
error — Unknown component.
Cause. An instance calls a component name that is not defined or imported.
Fix. Define the component, import it, or fix the name (see the suggestion hint).
sofa(0, 0) # error if no `component sofa` is in scopeE_UNKNOWN_FN
error — Unknown function.
Cause. A call uses a name that is neither a built-in nor a value-function in scope.
Fix. Define it with let f(…) = …, or fix the name.
let x = frobnicate(2) # errorE_UNKNOWN_REF
error — Unknown reference.
Cause. An expression references a name that is not bound in scope.
Fix. Declare it with let, pass it as a parameter, or fix the typo.
let x = y + 1 # error if `y` is undefinedE_VERT_SIZE
error — Vertical circulation must have a positive size.
Cause. A stair, elevator or escalator footprint's width or height evaluated to zero or a negative number, so there is no run to draw.
Fix. Give it a positive size W x H — the footprint the run occupies on this storey.
stair id=s at (0,0) size 900x0 dir up # error: zero depthE_VOID_SIZE
error — A floor void must have a positive size.
Cause. A void's width or height evaluated to zero or a negative number, so there is no opening in the floor plate to draw or to route circulation around.
Fix. Give it a positive size W x H — the hole's extent in plan.
void id=well at (2000,1000) size 0x3000 # error: zero widthE_WALL_THICKNESS
error — Wall must have a positive thickness.
Cause. A wall's thickness evaluated to zero or a negative number.
Fix. Give the wall a positive thickness.
wall exterior thickness 0 { (0,0) (1,0) } # errorE_WHILE_LIMIT
error — while exceeded its iteration cap.
Cause. A while ran more times than the safety cap allows (usually a condition that never becomes false).
Fix. Ensure the loop body updates a binding so the condition eventually fails.
let i = 0
while i < 1 { column at (0,0) size 1x1 } # error: i never changesE_WINDOW_WIDTH
error — Window must have a positive width.
Cause. A window's width evaluated to zero or a negative number.
Fix. Give the window a positive width.
window at (0,0) width 0 # errorW_ALIAS_MATCH
warning — A room's use was inferred from an indirect alias, not stated.
Cause. A room has no authored uses, and its function was guessed from its label via a non-canonical alias (an indirect term like powder → WC, foyer → entry) rather than a direct word (wc, entrance). The guess is reasonable but the intent is implicit, so a reader (or agent) cannot tell the classification was assumed.
Fix. Add an explicit uses … to the room stating the inferred function — the machine-applicable fix inserts it for you. This pins the classification without changing the room's describe() type.
room at (0,0) size 2000x1500 label "Powder" # warning: WC inferred from the alias "powder"; add `uses wc`W_BALCONY_NO_DOOR
warning — A balcony with no way onto it.
Cause. An outdoor balcony has no door and no window within one wall thickness of any of its edges, so the drawing shows a slab that cannot be reached. A window counts as well as a door, because a full-height window is a normal way onto a balcony.
Fix. Add a door (or a full-height window) on the wall the balcony hangs off — the usual fix — or move the balcony to the facade that already has one.
outdoor balcony at (2000,7200) size 4000x1600 # warning: no opening within reachW_BATH_VIA_BEDROOM
warning — Bathroom is reachable only through a bedroom.
Cause. Every door path from the entrance to this bathroom/WC passes through a bedroom. That is fine for a private en-suite, but a dwelling's main bathroom should open off circulation (a hall or living space), not a bedroom.
Fix. Add a door connecting the bathroom to a hall/living space, or route circulation so it is not reached only via a bedroom.
door id=d_bath at (5200,4000) width 800 wall partition # lint: bath only off the bedroomW_BEDROOM_NO_WINDOW
warning — Bedroom has no window.
Cause. A room labelled as a bedroom has no window on its perimeter (natural light / egress).
Fix. Add a window on an exterior wall of the room.
room at (0,0) size 3000x4000 label "Bedroom" # lint: no windowW_CIRCUITOUS_PATH
warning — A room is reached by a very roundabout path.
Cause. The walking distance from the entrance to a room is many times its straight-line distance — the room is reachable but only by a circuitous route (e.g. all the way around the plan). A coarse circulation fact (ADR 0008); the default ratio is generous so a normal tucked-away room does not trip it.
Fix. Add a more direct connection — a door or a hall — so the room is not reached the long way round.
room id=bed at (0,0) size 3000x3000 label "Bed" # only door is on the far side, forcing a long detourW_DIM_INSIDE
warning — A hand-written dimension line lands inside the building.
Cause. A dim's line is drawn at offset along the LEFT normal of from→to, so the ENDPOINT ORDER chooses which side it lands on. This dimension's line (not its witness lines) falls inside the room-extents bounding box, where it crosses room labels, furniture and poché instead of reading in the page margin. Almost always the endpoints are simply the wrong way round. Advisory: an interior dimension you actually want (a clear width inside a room) is legitimate — reverse it or leave the warning.
Fix. Swap the two endpoints — the machine-applicable fix does it for you, but only when the swap actually moves the line out. Swapping mirrors the line across the segment being measured (negating the offset does the same thing), so it reaches the outside only when that segment is at the building's edge. A dimension whose measured run cuts THROUGH the plan reads inside either way and carries no automatic fix: measure along a facade instead, or raise the offset until the line clears the building.
dim (0,6000)->(7000,6000) offset -500 text "7000" # warning: the -500 offset pulls the line back insideW_DIM_NO_WALL
warning — A dim faces/dim clear endpoint has no wall to measure to.
Cause. The endpoint-projection forms push each endpoint onto the FACE of the wall the measurement runs into, found as the nearest wall segment perpendicular to the dimension's own direction. One (or both) endpoints has no such wall within tolerance — the point is off the wall centerline, the wall is angled, or the plan has no wall there — so there is no face to project onto and the written point is measured as-is.
Fix. Put the endpoint on the centerline of the wall the dimension runs into (the room-rectangle corner coordinate), or drop the faces/clear keyword and write the face coordinate yourself.
wall exterior thickness 200 { (0,0) (5000,0) (5000,4000) (0,4000) close }
dim faces (0,9000)->(5000,9000) offset 600 # warning: nothing to project onto at y9000W_DIM_OVERLAP
warning — Two hand-written dimensions are drawn on top of each other.
Cause. Two dim statements measuring PARALLEL runs land in the same chain tier: their drawn bands — the dimension line, its station ticks, and the length text riding above the line — intersect, so on paper one reads through the other. ArchLang never re-staggers a hand-written dimension (the author's offset IS the tier control — ADR 0005, no invisible architect), so the collision is reported rather than silently laid out. Adjacent members of one chain that merely SHARE a station tick are not a collision and never warn, and two dims generated by one for are skipped — they share an offset expression, so no bump could separate them.
Fix. Move one of them out a tier: raise the magnitude of its offset (keeping its sign, which is the side it reads on). The machine-applicable fix computes the smallest whole number of chain tiers that clears the other dimension's line and text.
dim (0,-100)->(7000,-100) offset -300 text "7000"
dim (0,-100)->(4000,-100) offset -300 text "4000" # warning: both in the same tierW_DOOR_CLEARANCE
warning — Door is narrower than the minimum clear width.
Cause. A door's width is below the configured minimum passable width (default 700 mm).
Fix. Widen the door to at least the minimum clear width.
door at (0,0) width 500 wall exterior # lint: under 700 mmW_DOOR_OFF_WALL
warning — Door does not lie on any wall.
Cause. A door's position is not within tolerance of any wall segment, so it has no host.
Fix. Move the door onto a wall, or name its host with wall <id|category>. The diagnostic points at the nearest wall.
door at (9999,9999) width 900 # warning: not on a wallW_DOORWAY_BLOCKED
warning — A doorway's landing is blocked.
Cause. A piece of furniture/fixture sits in the clear landing space immediately on either side of a door opening, so you cannot pass through the doorway even when the leaf is open. This is the approach path, distinct from the leaf's swing arc (W_SWING_OBSTRUCTED). The warning states the landing depth required, the depth actually left, and the shortfall.
Fix. Move the obstruction clear of the opening by the shortfall the warning quotes (arch repair computes the smallest clearing shift), shrink it by that much on the axis facing the door, or move the door along its wall so its landing misses it.
door at (6000,3000) width 800
furniture wc at (5800,3050) size 700x400 # lint: WC blocks the doorwayW_DUP_ACC_METADATA
warning — Duplicate accTitle/accDescr.
Cause. A plan declares accTitle (or accDescr) more than once. Only one of each applies, so the last value silently wins.
Fix. Keep a single accTitle and a single accDescr; delete the extra line(s).
accTitle "A"
accTitle "B" # warning: "A" is discardedW_EMPTY_PLAN
warning — Empty plan.
Cause. The plan resolved to no drawable elements.
Fix. Add at least one element (wall, room, …).
plan "Empty" { units mm } # warningW_FIXTURE_BACK_TO_ROOM
warning — A fixture stands against a wall but faces the wrong way.
Cause. A fixture whose symbol has a distinct back — a plumbed one (a WC's cistern, a basin's tap, a counter's nosing) or a piece of furniture that simply has a front (a bed's headboard, a wardrobe's door line, a bookshelf's open face) — is touching a wall, but its back is turned to the room instead of to that wall: the drawing shows the WC's tank, or the headboard, sticking into the floor space. Position right, quarter-turn wrong: fixture symbols are drawn with their back on the TOP edge, so rotate is what aims them (0 = back to the north, 90 = east, 180 = south, 270 = west). A rotation-symmetric symbol (a shower tray, a round stool) never trips this, nor does arranged seating whose back to the room is a legitimate layout. A fixture that touches no wall at all is W_FIXTURE_FLOATING instead — and only where the piece genuinely needs one for services, which furniture does not.
Fix. Add the rotate that puts the back on the walled edge — the machine-applicable fix inserts it when exactly one edge is walled. Better still, place the piece with against wall <id> or in <room> anchor <edge> and let the rotation be derived.
furniture wc at (5200,5200) size 400x700 # warning: south wall behind it, cistern facing northW_FIXTURE_FLOATING
warning — A plumbing/kitchen fixture is not against a wall.
Cause. A fixture that conventionally needs a wall behind it (WC, basin, shower, sink, counter, stove, fridge…) sits with no wall backing any edge — it appears to float in the middle of the room.
Fix. Move the fixture so one edge is against a wall (supply/waste/venting runs in the wall), or remove it.
furniture wc at (3000,3000) size 400x700 # lint: no wall behind itW_FIXTURE_WRONG_ROOM
warning — Fixture is not inside its declared room.
Cause. A furniture item declared in <roomId> has part of its FOOTPRINT off that room's floor, so it is drawn partly (or mostly) in the wrong space. A 100 mm overhang is allowed on every side, because a room's outline runs down wall centrelines and a piece pushed against a room edge legitimately shares that band. Measured against the room's true floor, so a polygon or circle room is judged by its own shape and not by a bounding box.
Fix. Move the fixture inside the named room, or correct the in <roomId>.
furniture wc at (100,100) size 400x700 in bath # lint: not inside "bath"W_FURN_CLEARANCE
warning — A fixture's use-space is blocked.
Cause. The activity clearance directly in front of a fixture (WC, basin, sink, counter, stove…) is intruded by a free-standing piece of furniture, so the fixture can't be used comfortably. Other plumbing/kitchen fixtures are ignored, so a compact bathroom/kitchen run does not trip this. The warning states the catalogued clearance, the depth actually left, and the shortfall.
Fix. Move or shrink the obstructing furniture by the shortfall the warning quotes, turn the fixture so its front faces clear floor (its back must stay on a wall), or move the fixture to a wall run with the clearance free in front of it.
furniture stove at (0,0) size 600x600
furniture sofa at (0,650) size 2000x900 # lint: sofa blocks the stove frontW_FURNITURE_OVERLAP
warning — Two pieces of furniture overlap.
Cause. Two furniture/fixture rectangles occupy the same floor area, so they would physically collide — usually a coordinate or size mistake.
Fix. Move or resize one so they no longer intersect; leave a walkway between them.
furniture sofa at (300,300) size 2000x900
furniture bed at (1000,500) size 1500x2000 # lint: overlaps the sofaW_FURNITURE_WALL_COLLISION
warning — Furniture penetrates a wall.
Cause. A furniture/fixture rectangle intrudes into a wall's solid (it crosses the wall's thickness band rather than sitting flush against its face), so it would physically pass through the wall — a coordinate or size mistake. A piece merely touching the wall face is fine. Measured in the wall's own frame, so a wall at any angle is checked; a CURVED wall edge (arc) is not checked at all.
Fix. Move or resize the piece so it sits fully inside the room (against the wall face, not through it), or anchor it with against wall <id>.
furniture sofa at (350,2300) size 2000x900 # lint: crosses the partition at y3000W_GARAGE_TOO_NARROW
warning — A garage is too narrow to park in.
Cause. A room classified as a garage (an authored uses garage, or a label the use vocabulary reads as one — "Garage", or the aliases "carport" / "parking") measures less across its short side than the cars in it need: 2700 mm of clear width per bay, which is a body plus the room to open a door on each side. A garage with no car fixture drawn is measured against ONE bay — a room you could not park in does not become sound by having no car in it — and bicycle/motorcycle do not count toward the bay total. The warning states the width required, the width the room actually has, and the shortfall. The rule declines a POLYGON room rather than measuring its bounding box: a box's short side is not a concave floor's clear width, and a measurement taken from a shape's box instead of the shape is a defect class this compiler has shipped before. It is advisory and has no machine fix: widening a room moves every wall and opening around it, which is a geometric decision the compiler does not make (ADR 0005).
Fix. Widen the room to the figure the warning quotes, park fewer cars in it, or drop the uses garage tag if the room is not one (a store that happens to be called a garage classifies as one from its label alone — an explicit uses storage overrides that).
room id=g at (0,0) size 2500x6000 label "Garage" uses garage
furniture car at (300,300) size 1800x4600 in g # lint: 2500 mm across, one bay wants 2700W_HATCH_SCALE
warning — Hatch scale must be positive; using 1.
Cause. A wall material scale evaluated to zero or a negative number.
Fix. Use a positive scale.
wall exterior thickness 200 material brick scale 0 { (0,0) (1,0) }W_IMPORT_EMPTY_FILE
warning — Whole-file import binds an empty component.
Cause. import "<file>" as <name> turns a module's TOP-LEVEL drawable statements into one component, but that module's plan body has none (it may only declare components, or only level blocks — a storey is a page, so levels are dropped).
Fix. Draw in the module's plan body, or import one of its named components with import "<file>": <name>.
import "lib.arch" as lib # warning when lib.arch only declares componentsW_NO_ENTRANCE
warning — The plan has no exterior door.
Cause. The plan has rooms and an exterior wall but no door hosted on an exterior wall, so the building cannot be entered.
Fix. Add a door on an exterior wall.
wall exterior thickness 200 { (0,0) (4000,0) (4000,3000) (0,3000) close } # lint: no way inW_OPENING_OFF_WALL
warning — Opening does not lie on any wall.
Cause. A cased opening's position is not within tolerance of any wall segment, so it has no host.
Fix. Move the opening onto a wall, or name its host with wall <id|category>. The diagnostic points at the nearest wall.
opening at (9999,9999) width 1000 # warning: not on a wallW_OUTDOOR_OVERLAPS_ROOM
warning — A ground surface is laid over a room's floor.
Cause. An outdoor surface's extent overlaps the floor of a room by more than a shared edge. Almost always a coordinate slip — a terrace written from the wrong corner, or a lawn given the building's own extent. It matters because ground and floor are reported in SEPARATE totals (totals.outdoor_area_m2 and totals.floor_area_m2), so the overlapping piece is counted twice by anything that adds them for a plot figure. A surface that merely touches a room along its edge — a patio flush against the house — does NOT trip this.
Fix. Move or resize the surface so it sits outside the building's rooms. If the overlap is deliberate (a covered terrace drawn under a room), the two are genuinely different things and one of them is the wrong element.
room id=liv at (0,0) size 5000x4000 label "Living"
outdoor paving at (1000,1000) size 3000x2000 # warning: on the living-room floorW_PATH_TOO_NARROW
warning — The walk to a room squeezes below a passable width.
Cause. The widest route from the entrance into a room (or between a key pair of rooms, e.g. bedroom→bath) has an unavoidable pinch narrower than the minimum passable clear width — a too-narrow door/opening, or furniture crowding the way. A coarse fact from the circulation nav grid (ADR 0008); the number is grid-quantised.
Fix. Widen the tightest door/opening on the route to at least the minimum, move the furniture pinching it, or add a second way in so the pinch is avoidable. There is no machine-applicable fix: the bottleneck is a nav-grid cell, not a named element, so nothing can be rewritten for you.
door at (4000,1500) width 600
furniture cabinet at (3600,300) size 700x1200 # lint: the way through squeezes below 700 mmW_POCKET_RUN
warning — A pocket door has no wall to slide into.
Cause. A pocket door's panel disappears into a cavity inside the host wall, so the wall must continue past the slide-side jamb by at least the door's own width plus end clearance. This measures the run from that jamb to the end of the host segment, TRUNCATED at the near edge of any other opening (a window or a second door) that falls inside it — a panel cannot slide through a window either. The warning states what the run has to be, what is actually there, and the shortfall. The threshold, and a deliberate divergence from the source it is borrowed from: the required run is width + max(50 mm, width × 5%) (pocketRunClearanceMm in the lint ruleset). The rule is modelled on planscript-rust's pocket_door_wall_run, which requires a flat width × 1.05 — but a pure ratio is wrong on narrow doors: a 700 mm pocket would ask for 35 mm of end clearance, which does not fit a real jamb and pull. We are not publishing a comparison against that project, so matching its constant buys nothing, and architectural correctness outranks reference-comparability. The two extra things this rule does that the reference does not: it subtracts intervening openings, and it carries its remedies as structured fixes rather than printed prose.
Fix. Reverse the slide (slide left ↔ slide right) — a machine-applicable fix, emitted only after the reverse run is recomputed and proved to satisfy; move the door along its wall so the pocket lands on solid wall; or lengthen the wall. Narrowing the door is deliberately NOT offered as a fix: rewriting the author's stated width to satisfy a checker is the constraint-laundering pattern this project rules out, and it would also walk into W_DOOR_CLEARANCE.
wall w1 thickness 200 { (0,0) (3000,0) }
door pocket on w1 at 80% width 900 slide right # lint: only ~600 mm of runW_ROOM_DISCONNECTED
warning — Room has no door — it can't be entered.
Cause. No door lies on any of the room's walls, so there is no way into the room.
Fix. Add a door on one of the room's walls.
room id=r at (0,0) size 3000x3000 # lint: no door on its perimeterW_ROOM_LABEL_OUTSIDE
warning — A room's explicit label anchor falls outside the room.
Cause. label "…" at (x,y) pins the label and area text at a point that is not inside the room's floor, so the text will be drawn over whatever is there instead.
Fix. Move the anchor inside the room, or drop the at (…) — automatic placement uses the rectangle's centre, the circle's centre, or a polygon's area centroid (falling back to the interior point furthest from any edge where a concave ring puts that centroid off its own floor), so it lands inside either way.
room polygon (0,0) (6000,0) (6000,6000) (0,6000) label "Hall" at (9000,9000) # warningW_ROOM_NO_CLEAR_PATH
warning — A room cannot be entered or crossed.
Cause. Furniture, fixtures, door swings and their clearances fill the room so densely that a person stepping through a door/opening has no clear floor path into the usable space — the room is technically reachable but physically blocked.
Fix. Open up the layout: move or shrink the furniture nearest the door so there is a continuous walkable strip from each entrance into the room.
furniture shower at (5000,3000) size 2000x2000 # lint: fills the bathroom against its only doorW_ROOM_NO_FIXTURE
warning — Bathroom or kitchen has no fixtures.
Cause. A room labelled as a bathroom or kitchen contains no plumbing/kitchen fixture (WC, basin, shower, sink, counter…), so it is drawn as an empty box.
Fix. Place the expected fixtures — e.g. import lib/fixtures.arch and add a wc, basin, shower, or kitchen_sink.
room at (4000,4000) size 3000x2000 label "Bath" # lint: no fixtures insideW_ROOM_NOT_ENCLOSED
warning — Bathroom is not fully enclosed.
Cause. A run of this bathroom/WC's perimeter is not backed by a wall, so it is open to the adjacent space — a privacy problem for a wet room (a partition that stops short is the usual cause).
Fix. Extend the partition so the room's perimeter is walled on all sides (a door/window in the wall is fine — only a missing wall counts).
wall partition thickness 100 { (4000,0) (4000,4000) } # lint: stops short, bath left openW_ROOM_NOT_EQUATOR_FACING
warning — A habitable room has windows, but none faces the equator side.
Cause. The plan declares site, so the equator-facing side is known (S in the northern hemisphere, N in the southern), and a habitable room — a bedroom, living or dining space — has at least one window with none of them on that aspect. This is a drafting heuristic, not a measured daylight outcome: it says the room's windows do not face the equator, and nothing more. A south window in Reykjavík and one in Singapore are not the same daylight, and this rule does not distinguish them (there is no sun model, latitude or date anywhere in ArchLang). The rule cannot fire at all in a plan with no site, and a room with NO window is W_BEDROOM_NO_WINDOW's report, not this one.
Fix. Move a window onto the room's equator-facing facade, or accept the aspect — an urban plot often has no equator-facing wall to spare. There is deliberately NO machine fix: the remedy is a geometric decision (which facade, which wall, what else it displaces) and the compiler does not make those (ADR 0005).
site { street north } # equator side is S
room id=liv at (0,0) size 4000x3000 label "Living"
window on north_wall at 50% width 1200 # warning: the only window faces NW_ROOM_OVERLAP
warning — Rooms overlap.
Cause. Two room rectangles intersect.
Fix. Adjust positions/sizes if the overlap is unintended (it is allowed).
room at (0,0) size 2000x2000
room at (1000,0) size 2000x2000 # warningW_ROOM_TOO_SMALL
warning — Room is implausibly small.
Cause. A room's floor area is below the configured minimum (default 4 m²).
Fix. Increase its size, or merge it into an adjacent space.
room at (0,0) size 1000x1000 label "Closet" # lint: 1 m²W_ROOM_UNREACHABLE
warning — Room cannot be reached from the entrance.
Cause. The building has an entrance, but this room has no door/opening path back to the exterior — it is sealed off from the circulation.
Fix. Add a door or cased opening linking it (directly or through a hall) to a space that reaches the entrance.
room at (5000,0) size 3000x3000 label "Store" # lint: no path from the entranceW_SANITIZED_CONFIG
warning — A disallowed config value was stripped.
Cause. A theme/style value contained markup or a data: URL and was blanked for safety.
Fix. Use a plain colour/string value (no <, >, or url(data:…)).
theme { wall: "<script>" } # warning: strippedW_SCALE_OVERFLOW
warning — The drawing does not fit the declared paper at the declared scale.
Cause. The plan declares a paper size, so scale is operative: the building's outer-face extent has to fit the sheet minus its margins, the dims auto dimension bands, the bottom chrome band (scale bar + title block) and the margin-table row that schedule rooms / legend occupy below it. At the scale in force it does not. Your scale is NEVER silently overridden — a drawing is issued at the scale printed in its own title block — so nothing is clipped: the drawing keeps its sheet margin where it can, and the page grows past the sheet when it cannot. Note that the SHEET FURNITURE counts, not just the building: adding a schedule to a tight sheet can raise this with no change to the plan's geometry. Advisory: an oversize sheet you intend to trim or tile is legitimate.
Fix. Pick a coarser scale (a larger denominator draws the building smaller), move up a paper size, drop a margin table you can do without, or drop the scale line and let the sheet auto-fit choose the finest scale from 1:50 / 1:100 / 1:200 / 1:500.
paper A4 landscape
scale 1:50 # warning on a 20 m building: 1:100 or `paper A2` fits, or omit `scale` to auto-fitW_STAIR_UNMATCHED
warning — A run of vertical circulation appears on only one storey.
Cause. In a multi-storey plan the ONLY thing that joins two floors is identity: a stair/elevator/escalator with the same id in two level blocks is one shaft. This id appears on exactly one storey, so it connects nothing — usually a typo in the id, or the matching run was never drawn on the floor above or below. Known limitation: a top-floor stair that genuinely goes only to a roof hatch, and a lift that stops short of a storey it passes, both trip this rule; it is advisory, so leave it.
Fix. Draw the same run with the SAME id on the neighbouring storey (each storey declares its own dir — up on the lower floor, down on the upper one), or fix the id.
level 1 "G" { stair id=s at (0,0) size 900x2600 dir up }
level 2 "1" { } # warning: "s" is on level 1 onlyW_SWING_OBSTRUCTED
warning — Door swing is obstructed.
Cause. The quarter-circle a door leaf sweeps overlaps a piece of furniture/fixture or another door's swing, so the door cannot open fully. The warning states the clear radius the swing needs, what it actually has, and the shortfall.
Fix. Hang the leaf on the other jamb (hinge left|right) — a machine-applicable fix when the flipped swing is proved clear; or open it the other way (swing in|out), move the door along its wall, move the obstruction (arch repair), narrow the leaf to the width the warning quotes (never below the minimum passable width — that relocates the problem into W_DOOR_CLEARANCE), hang no swinging leaf at all (a sliding, pocket or barn door sweeps nothing, so this rule cannot apply to it), or make it a leafless opening.
door at (4000,1500) width 900 swing in # lint: leaf sweeps onto the bedW_SWING_ROOM_NOT_ADJACENT
warning — swing into <room> names a room the door does not border.
Cause. A door's swing into <room> points the leaf toward a room, but that room does not share the door's host wall (its box does not touch the wall within tolerance), so which side it means is undefined.
Fix. Point swing into at a room the door actually opens onto, or use explicit swing in|out. The door falls back to its default swing.
door on w1 at 50% width 800 swing into faraway # warning: not on this wallW_UNKNOWN_MATERIAL
warning — Unknown wall material; using the default hatch.
Cause. A wall material name is not one of the known hatches.
Fix. Use a known material (e.g. brick, concrete, insulation, tile) or omit it.
wall exterior thickness 200 material marble { (0,0) (1,0) } # warningW_UNKNOWN_STYLE_KEY
warning — Unknown style key.
Cause. A style <kind> { … } block uses a key not valid for that element kind.
Fix. Use a valid key (e.g. fill / stroke / label, depending on the kind).
style room { nope: "#000" } # warningW_UNKNOWN_THEME_KEY
warning — Unknown theme key.
Cause. A theme { … } block uses a key that is not a theme property or alias.
Fix. Use a known theme key (see the language reference / hover).
theme { nope: "#000" } # warningW_WINDOW_OFF_WALL
warning — Window does not lie on any wall.
Cause. A window's position is not within tolerance of any wall segment, so it has no host.
Fix. Move the window onto a wall, or name its host with wall <id|category>. The diagnostic points at the nearest wall.
window at (9999,9999) width 1200 # warning: not on a wall