Skip to content

Update ​

Edit existing scene entities — properties and geometry. Accessed via snaptrude.design.update.

Migrated from the removed entity.space.{update, updateGeometryFromProfile, bulkUpdate}. Only provided fields change; each call is undoable. Failures throw (the RPC rejects).

Performance

Editing many spaces? Use the plural spaces(items) — one host round-trip for the whole batch — rather than looping space. See Performance.

Types ​

PluginSpacePropertyUpdates ​

Sparse property changes for a space (all optional).

PropertyTypeDescription
room_typestringRoom label
massTypePluginMassTypeMass type
spaceTypePluginSpaceTypeSpace type
areaClassPluginAreaClassArea class (NET / GROSS / EXCLUDED)
departmentIdPluginDepartmentIdDepartment

PluginSpaceGeometryUpdate ​

Geometry replacement — re-extrude a profile.

PropertyTypeDescription
profileProfileHandleNew footprint profile
extrudeHeightnumberNew extrude height

PluginUpdateSpaceItem ​

One space to update via spaces. { space: ComponentHandle; properties?: PluginSpacePropertyUpdates; geometry?: PluginSpaceGeometryUpdate }.

PluginStaircaseParamUpdates ​

Sparse parametric changes for a staircase (all optional) — the same fields the staircase properties panel exposes. Dimensions are in Snaptrude (engine) units. See design.query.getStaircaseParams for the paired read.

PropertyTypeDescription
staircaseHeightnumberTotal rise
stepsnumberStep count
risernumberRiser height
treadnumberTread depth
widthnumberFlight width
depthnumberFlight depth
baseOffsetnumberBase offset from the storey
storeyHeightnumberStorey height (when decoupled)
wellSizenumberWell size (well-based presets)
landingWidthnumberLanding width (landing-based presets)
flightStartDistAfterTurnnumberFlight start distance after a turn
isStoreyHeightUnlockedbooleanDecouple height from the storey
isStaircaseHeightUnlockedbooleanDecouple height from steps × riser

MassParametersPatch ​

The argument of parameters: either a partial of a mass record's values (plus an optional operations list) — keys you leave out stay as they are — or the whole MassParametersRecord you read from design.query.getParameters, edited. kind and version are immutable. Points and axes are world coordinates in Snaptrude (engine) units, exactly as getParameters reports them.

Scalars and points merge by key ({ radius: 8 } changes only the radius); lists and records — contour, sections, path, profile, options, operations — replace whole when present, so send the complete list or bag you read ({ operations: [] } drops every operation; { options: { endScale: 2 } } drops every other recorded option).

Patch keyValue
any values key of the record's kindnumber, a { x, y, z } point, a point array, a ContourRecord (or array), or an options object
operationsOperationRecord[] — the whole list, in order

An optional key the record does not carry yet may still be patched in when the kind allows it — that is how a straight extrusion acquires twistInDegrees or topScale, and how an options-less loft or sweep acquires options. levels is the exception in both directions: it is not a dimension but how the twist was built, so a straight extrusion has no such key (a first-twist patch carrying it is refused as an unknown key — send the angle, not the section count), and on a twisted mass it may only be echoed back unchanged. The host re-resolves it whenever an edit changes the angle.

PluginWallUpdates ​

Sparse changes for a wall (all optional; at least one required). Dimensions are in Snaptrude (engine) units and must be > 0.

PropertyTypeDescription
thicknessnumberWall thickness
heightnumberWall height
typestringConvert the wall to another wall type — a name, label, or wall:-prefixed id from design.types.list("wall")

PluginSlabUpdates ​

Sparse changes for a slab-family element — slab / floor / roof / ceiling. Values are in Snaptrude (engine) units; thickness must be > 0.

overhang is only available on slabs and roofs (the panels' Overhang slider) — floors and ceilings reject it with PRECONDITION_FAILED.

PropertyTypeDescription
thicknessnumberElement thickness
overhangnumberAbsolute overhang offset (negative insets the edge) — slab / roof only

PluginObjectType ​

Object types setObjectType can turn a mass into — the design.query type vocabulary: "wall" | "roof" | "slab" | "floor".

Functions ​

grid(grid, patch) ​

Update a structural grid's group-level fields with a sparse patch — default line styling, absolute angle, and per-storey 2D visibility. Only provided fields change. Wing- and line-level updates live on the grids entity family: design.grids.updateWings / updateLines.

Each changed field routes through the exact setter the native panel uses and commits its own undoable command — identical to editing that field in the panel. angle is an absolute target in degrees (CCW about +Y).

  • Parameters:
    • grid: ComponentHandle — The grid group to update
    • patch:
      • angle?: number — absolute angle, degrees
      • props?: { style?, weight?, color?, showStart?, showEnd? } — group defaults
      • storeyVisibility?: Array<{ storey: number; visible: boolean }> — per-storey 2D-plan visibility
  • Returns: true once applied
ts
const [grid] = await snaptrude.design.query.listGrids();
await snaptrude.design.update.grid(grid, { angle: 45, props: { style: "DASHED" } });

space(space, options) ​

Update ONE space — sparse properties and/or a geometry re-extrude. Undoable.

  • Parameters:
    • space: ComponentHandle — The space to update
    • options: { properties?: PluginSpacePropertyUpdates; geometry?: PluginSpaceGeometryUpdate }
  • Returns: the updated space's echoed PluginSpaceUpdateResult
  • Throws: for an unknown/forged handle or an engine failure
ts
await snaptrude.design.update.space("space-id", { properties: { room_type: "Office" } });

spaces(items) ​

Update many spaces in one host round-trip (bulk plural of space) — always prefer this over looping space; it also commits as a single undoable operation. Validate-all-or-throw; one command.

  • Parameters:
    • items: PluginUpdateSpaceItem[]
  • Returns: one PluginSpaceUpdateResult per item, in input order
ts
await snaptrude.design.update.spaces([
  { space: "s1", properties: { spaceType: "Room" } },
  { space: "s2", geometry: { profile, extrudeHeight: 4 } }
]);

setLabel(component, label) ​

Set a component's Label — the same editable Label field the properties panel shows (doors, windows, furniture, spaces, and every other labelled component). The paired read is design.query.getLabel. Undoable; the canvas label text updates immediately.

Strictly per component: labelling one door of a placed family never touches its sibling doors (the panel's Label edit, by contrast, applies to the whole family). On legacy masses without a space type, panel parity applies — a label matching a room-type preset with a height (e.g. "Water Body") can also adjust the mass's height and material, exactly like typing it in the panel.

  • Parameters:
    • component: ComponentHandle — The component to relabel
    • label: string — New label text (non-empty; leading/trailing whitespace trimmed)
  • Returns: true once the label is applied
  • Throws: when the component is locked, the handle is gone/forged, the label is empty, or the component has no mesh to label.
ts
// Door tag numbering: label every door as D-<storey>-<n>, numbered per storey
await snaptrude.design.selection.setByFilter({ types: ["door"] });
const doors = await snaptrude.design.selection.get();
const counts = {};
for (const door of doors) {
  const { storey = 0 } = await snaptrude.design.query.getProperties(door);
  counts[storey] = (counts[storey] ?? 0) + 1;
  await snaptrude.design.update.setLabel(
    door,
    `D-${storey}-${String(counts[storey]).padStart(2, "0")}`
  );
}

staircase(staircases, params) ​

Update the parametric fields of one or more preset staircases — riser, tread, width, depth, step count, height, base offset, and the type-specific well/landing/flight fields. Values are Snaptrude (engine) units; the engine round-trips each dimension through the panel's display representation, so a plugin read → write returns the staircase to the exact panel values.

Presets-only: this edits the parameters of an existing preset staircase; it does not re-type it. staircaseHeight / steps / riser are coupled (height = steps × riser) and governed by the two lock booleans — the locks are applied first so the coupled recompute sees them. Every field rebuilds the geometry, and every edit across every staircase commits as one undo batch. A locked or non-staircase handle rejects the whole call before any geometry is rebuilt.

ts
const [stair] = await snaptrude.design.query.listStaircases();
await snaptrude.design.update.staircase([stair], { steps: 16, width });

parameters(component, patch) ​

Edit a parametric mass by patching its creation recipe and rebuilding the solid in place — the mass keeps its id, storey, materials, position and linked copies; only the geometry changes. This is the write pair of design.query.getParameters: read the current record first, patch the keys you mean, and send them back. Never delete-and-recreate to change a size — that mints a new component and loses its id, materials and linked copies.

patch is a MassParametersPatch: a partial of record.values (plus an optional operations), or the whole record you read back, edited. A key you leave out is unchanged — including operations. Lists and records (options included) replace whole when present. kind and version are immutable: to change the kind, build a new mass. To change a fillet radius, edit operations[i].radius in the record you read and send { operations } back. A patch that changes nothing returns the current record and records no edit (no undo step).

The solid is rebuilt in memory first, then swapped onto the SAME component, so a failure leaves the model untouched; every linked copy regenerates together (one undo step, saved and synced to collaborators like any geometry edit). Kernel kinds — the four primitives, revolution, both sweeps, loft, a twisted or tapered extrusion, and any recipe carrying operations — run on OpenCascade, so expect a short pause.

The reply is the new record: read it rather than re-calling getParameters.

  • Parameters:
  • Returns: MassParametersRecord — The complete post-edit record in world coordinates (what getParameters now returns)
  • Throws: PRECONDITION_FAILED when the mass carries no live recipe, when it (or a linked copy) is locked — the recipe stays intact; unlock and retry — when a recorded operation's edge/face selectors no longer resolve on the rebuilt base, or when this edit is the first twist or taper, or the straightening, of a mass that already carries a shell, fillet or chamfer (an offset selects nothing and is not affected; the message names the two-step re-apply); VALIDATION for a key the kind does not have, kind/version in a partial patch, or a value outside the constructor's own rules; OPERATION_FAILED when the kernel cannot build the edited recipe (the model is left unchanged)

The three PRECONDITION_FAILED causes want different responses

No live recipe — the mass was built from a boolean, a split, brepFromFaces/brepFromMesh, or drawn; was edited free-form since (push/pull, move face, boolean); or was scaled with the transform tool. getParameters returns null for exactly these. Do not retry — rebuild it with a recipe constructor and say so (for a scaled mass, undo the scale).

Locked — the message says the mass (or a linked copy) is locked. The recipe is intact and getParameters still returns the full record — a lock is invisible to the read, so this is the one refusal it does not predict. Unlock the mass (design.unlock) and call again; never rebuild or delete a mass the user locked, and never report it as non-parametric.

Selector drift — the message names an operation and an edge: a recorded fillet/chamfer/shell no longer finds its edges on the rebuilt base (the base edit changed the topology). Re-select the edges on the new shape and re-apply that one operation.

First twist or taper of a mass that already carries a shell, fillet or chamfer (an offset selects nothing and is not affected) — a straight extrusion is built by the engine and a twisted one through the kernel, which numbers the faces differently, so every recorded selector would resolve against different geometry. The edit is refused before the rebuild, with the two-step re-apply spelled out: send { twistInDegrees, operations: [] } first, read the new shape (getBrep → brep.listFaces → face.getCentroid picks the top by position, never by the old index), then send { operations } back with the new index. The mass keeps its id across the two calls; in the agent lane one worker body groups them into a single undo step — a plugin calling directly records two. Once a mass is twisted, later twist and taper edits keep their selectors and need no re-apply.

A mass standing on its storey's base keeps that base where it is through an edit, however much the rebuild grew — the solid grows upward, and the record moves with it. A free-floating mass keeps its placement instead and grows about itself.

ts
// Make the dome's radius 8 m (internal units)
const before = await snaptrude.design.query.getParameters(dome);
// { kind: "sphere", version: 1, values: { centre, radius: 19.685 } }
const after = await snaptrude.design.update.parameters(dome, { radius: 31.496 });

// Twist a tower that already exists — `levels` is the host's, not yours
await snaptrude.design.update.parameters(tower, { twistInDegrees: 90 });

// Change the fillet on a rounded column: read → edit → send the array back
const rec = await snaptrude.design.query.getParameters(column);
const operations = rec?.operations ?? [];
if (operations[0]?.op === "fillet") {
  operations[0].radius = 1.181;
  await snaptrude.design.update.parameters(column, { operations });
}

wall(component, updates) ​

Edit a wall — its thickness and/or height (the same command the properties panel's Thickness/Height fields drive) and/or its wall type (the panel's Wall Types dropdown: converts the wall to another type, rebuilding its layer stack and materials, stacked-wall conversions included). Sparse and undoable; the geometry rebuilds, dimension lines anchored to the wall refresh, and stacked-wall companions and hosted fenestration are handled exactly as the panel does. Dimensions are in Snaptrude (engine) units and must be > 0.

type accepts the tokens design.types.list("wall") returns — the type name, its label, or the wall:<name> id. When combined with dimensions the type conversion is applied first, so an explicit thickness/height wins over the new type's defaults. Re-applying the wall's current type is a no-op.

  • Parameters:
  • Returns: PluginDesignChangeResult — the affected wall
  • Throws: for a non-wall handle, a locked wall, an unknown/forged handle, an unknown wall type, a conversion the engine rejects (e.g. a curved wall thinner than the new type's minimum thickness), or no field supplied

Rebuilds replace the wall — re-bind from affected

A type conversion (and a thickness edit on a parametric wall) rebuilds the wall, replacing it with a new component. Your input handle is then dead (further calls throw HANDLE_INVALID); affected[0] carries the replacement's handle — use it for any follow-up calls.

ts
const walls = await snaptrude.design.query.listWalls({ storeys: [1] });
for (const wall of walls) await snaptrude.design.update.wall(wall, { thickness: 230 });

// Convert a wall to another type from the panel's Wall Types dropdown.
// The conversion rebuilds the wall — keep working with the handle it returns.
const [wallType] = await snaptrude.design.types.list("wall");
const { affected } = await snaptrude.design.update.wall(walls[0], { type: wallType.id });
const converted = affected[0]; // NOT walls[0] — that handle is dead after the rebuild

slab(component, updates) · floor · roof · ceiling ​

Edit a slab-family element — its thickness (the same command the properties panel's Thickness field drives), and on slabs and roofs also its overhang (the panels' Overhang slider). One method per kind (slab, floor, roof, ceiling); they share the underlying commands and each rejects a handle of the wrong kind. Sparse and undoable; the element rebuilds and dimension lines anchored to it refresh. Values are in Snaptrude (engine) units; thickness must be > 0.

overhang is an absolute offset (not a delta): re-applying the current value is a no-op, 0 removes the overhang, and a negative value insets the edge. Plinth/basement slabs and elements whose overhang is disabled have no Overhang control — setting overhang on them (or on any floor/ceiling) throws PRECONDITION_FAILED. When both fields are given, thickness applies first, then overhang (each is its own undo entry, exactly like two panel edits).

  • Parameters:
  • Returns: PluginDesignChangeResult — the affected element
  • Throws: for a wrong-kind handle, a locked element, an unknown/forged handle, an overhang on an element without one, or no field supplied
ts
const [slab] = await snaptrude.design.query.listSlabs();
await snaptrude.design.update.slab(slab, { thickness: 250, overhang: 200 });

const [roof] = await snaptrude.design.query.listRoofs();
await snaptrude.design.update.roof(roof, { overhang: 600 });

buildableEnvelope(buildableEnvelopeId, sitePolygon, lengthUnit, setbacks, verticalCap, floorToFloor, farRatio?, lotCoverageMaxPct?) ​

Update an existing parametric buildable envelope in place. buildableEnvelopeId is required and must match an envelope previously created with design.create.buildableEnvelope; the remaining arguments fully re-describe the envelope (nothing is inherited from its current state). This is the canonical home of entity.buildableEnvelope.update (now deprecated).

  • Parameters:
    • buildableEnvelopeId: string — Existing envelope id to update; non-empty
    • sitePolygon: PluginBuildableEnvelopePolygonVertex[] — Site polygon vertices in lengthUnit; minimum 3 vertices
    • lengthUnit: "ft" | "m" — Unit used by all length fields
    • setbacks: PluginBuildableEnvelopeSetbackTier[] — Setback profile, ground tier first; minimum 1 tier
    • verticalCap: PluginBuildableEnvelopeVerticalCap — Maximum height or floor count
    • floorToFloor: number — Required floor-to-floor height in lengthUnit
    • farRatio: number (optional) — Optional FAR value, positive when provided
    • lotCoverageMaxPct: number (optional) — Optional lot coverage cap, 0..100
  • Returns: { buildableEnvelopeId: string } — The id of the updated envelope
  • Throws: If validation fails, the envelope does not exist, or generation produces no renderable geometry
ts
const { buildableEnvelopeId } = await snaptrude.design.update.buildableEnvelope(
  existingId,
  [
    { x: 0, z: 0 },
    { x: 100, z: 0 },
    { x: 100, z: 80 },
    { x: 0, z: 80 }
  ],
  "ft",
  [{ aboveHeight: 0, front: 10, side: 5, rear: 10 }],
  { kind: "max_height", maxHeight: 175 },
  12
);

setElevation(component, elevation) ​

Set a component's absolute world elevation — moves it vertically so its base (the bounding-box bottom, world Y) lands at elevation. Composed over the canonical command-backed move machinery, so it is undoable and persisted exactly like dragging the element up or down; per-type invariants (e.g. a staircase's base offset) stay in sync. elevation is in Snaptrude (engine) units. Re-applying the current elevation is a no-op.

  • Parameters:
    • component: ComponentHandle — The component to move vertically
    • elevation: number — Target world elevation of the component's base
  • Returns: PluginDesignChangeResult — the affected component
  • Throws: for a locked component or an unknown/forged handle
ts
const [roof] = await snaptrude.design.query.listRoofs();
await snaptrude.design.update.setElevation(roof, 3000);

setBaseOffset(component, offset) ​

Set a component's base offset — its vertical distance above its own storey's base level. Moves the component so its base lands at storeyBase + offset, composed over the same command-backed move machinery as setElevation (undoable, persisted, per-type invariants kept in sync). Use this when you want an offset relative to the storey rather than an absolute world height. offset is in Snaptrude (engine) units; 0 sits the base flush with the storey base. Re-applying the current offset is a no-op.

  • Parameters:
    • component: ComponentHandle — The component to offset
    • offset: number — Distance of the component's base above its storey base
  • Returns: PluginDesignChangeResult — the affected component
  • Throws: for a locked component, a component with no storey, or an unknown/forged handle
ts
const [stair] = await snaptrude.design.query.listStaircases();
await snaptrude.design.update.setBaseOffset(stair, 0);

setStorey(components, storey) ​

Reassign one or more components to another storey — the same operation as the properties panel's Story dropdown, working across element kinds exactly like the panel (walls, slabs, masses, furniture, staircases, ...). Each component moves vertically to the target storey's level (per-kind placement rules — a slab sits at the storey base, a wall on it), its storey assignment and children update, stale canvas labels are removed, and storey visibility flags re-apply. All moves commit as one undoable operation; parametric walls/floors are made non-parametric first, exactly as the panel does.

storey is an integer storey number in the entity.story convention (1 ground, -1 first basement; 0 does not exist) and must already exist in each component's building — this call never creates storeys (use entity.story.create first; the panel's dropdown likewise only offers existing storeys). Components already on the target storey are skipped as no-ops (their custom elevation is preserved) and are not echoed in affected.

All guards run up front (all-or-nothing): a locked component, a missing storey, or a bad handle rejects the whole call before anything moves.

  • Parameters:
    • components: ComponentHandle[] — The components to reassign
    • storey: number — Target storey number (integer, core.storeys convention)
  • Returns: PluginDesignChangeResult — the components actually reassigned
  • Throws: for a non-existent target storey, a locked component, or an unknown/forged handle
ts
// Move the current selection up to storey 2
const selection = await snaptrude.design.selection.get();
const { affected } = await snaptrude.design.update.setStorey(selection, 2);
console.log("moved", affected.length, "components");

setObjectType(components, objectType) ​

Change the object type of one or more masses — turn a mass into a real wall, roof, slab or floor: the properties panel's Object Type dropdown, headless. The geometry is kept exactly as it is (a wedge stays a wedge; nothing is flattened to a default thickness), so a sloped mass built with design.create.massFromBrep becomes a sloped roof or a raked wall. The component keeps its handle, label and storey; it gains the target type's construction layers and properties, and the type's default material when the mass still wore the default. One undoable operation for the whole list; undo turns them back into masses.

Instances convert as a family: passing one instance (or the source) of an instanced mass converts its source and every sibling; affected echoes every visible member (the hidden instancing template converts too but is not listed). A converted component cannot be converted again (same rule as the panel). A converted wall has no parametric centerline: it hosts doors and windows and exports, but neighbours do not re-mitre against it.

  • Parameters:
  • Returns: PluginDesignChangeResult — the visible components converted: the same handles, plus any instance siblings pulled in by family expansion
  • Throws: before anything changes (all-or-nothing) when a component is not a mass, is a plinth, is locked or in a locked bucket, already had its type changed, or when a handle is gone/forged
ts
const brep = await snaptrude.core.geom.create.brepFromFaces(wedgeFaces);
const wedge = await snaptrude.design.create.massFromBrep(brep, "Gable end");
const { affected } = await snaptrude.design.update.setObjectType([wedge], "wall");
console.log(await snaptrude.design.query.getEntityType(affected[0])); // "wall"

Errors ​

Failed calls reject with a typed PluginError — see Error Handling. Conditions specific to this namespace:

CodeThrown byWhendetails
VALIDATIONspace, spacesgeometry.extrudeHeight is zero or negative (must be > 0)extrudeHeight — the offending value
VALIDATIONwall, slab, floor, roof, ceilingNo field supplied, or a thickness/height that is zero or negative (must be > 0)—
HANDLE_INVALIDspace, spacesAn id does not resolve to a live space/mass (not-found and wrong-kind collapse to the one code); the geometry.profile handle cannot be resolved—
HANDLE_INVALIDall element editorsThe component id is gone or forged—
PRECONDITION_FAILEDwall, slab, floor, roof, ceilingThe handle is not of the expected kind, or the element is locked—
PRECONDITION_FAILEDwalltype names an unknown wall type (see design.types.list("wall"))type — the offending token
PRECONDITION_FAILEDslab, floor, roof, ceilingoverhang set on an element without one: any floor/ceiling, a plinth/basement slab, or an element whose overhang is disabled—
VALIDATIONparametersA key the record's kind does not have (the message lists the kind's keys), kind/version in a partial patch, or a value outside the constructor's own rules (torus tube ≥ ring, revolution angle ∉ (0, 360], a profile crossing its axis, a spline with fewer than degree + 1 poles)—
PRECONDITION_FAILEDparametersThe mass carries no live recipe (getParameters is null — built from a boolean/split/brepFromFaces/brepFromMesh/drawn, edited free-form since, or scaled with the transform tool) — do not retry; or the handle is not a mass—
PRECONDITION_FAILEDparametersThe mass or one of its linked copies is locked — the recipe is intact and getParameters still returns it; unlock and call again, never rebuild—
PRECONDITION_FAILEDparametersA recorded operations entry's edge/face selectors no longer resolve on the rebuilt base — the message names the operation and edge. hint: re-select on the new shape and re-apply that operation—
OPERATION_FAILEDparametersThe kernel could not build the edited recipe, or the rebuilt solid could not be committed — the model is left unchanged—
PRECONDITION_FAILEDsetStoreyThe target storey does not exist in a component's building, or a component is lockedstorey — the missing value
PRECONDITION_FAILEDsetObjectTypeA component is not a mass, is a plinth, is locked or in a locked bucket, or already had its type changedhandles — the offending component
OPERATION_FAILEDsetObjectTypeThe engine could not convert a component (no command was recorded — undo is unavailable for that step)engineCode: "TYPE_CHANGE_FAILED"
PRECONDITION_FAILEDsetElevation, setBaseOffsetThe component is locked; setBaseOffset also throws when the component has no storey—
HANDLE_INVALIDgridThe id is unknown or does not belong to a grid group—
PRECONDITION_FAILEDgridThe grid is lockedhandles — the grid id
OPERATION_FAILEDspace, spaces, setElevation, setBaseOffsetThe engine cannot apply the geometry/property update, or the vertical move is rejected (hosted/constrained)—
OPERATION_FAILEDwallThe engine rejected a type conversion without applying it (e.g. a curved/non-orthogonal wall thinner than the new type's minimum thickness)type — the requested type name
OPERATION_FAILEDslab, roofThe engine could not rebuild the overhang geometry (e.g. a slanted slab whose thickness varies, or a profile that cannot be offset)engineMessage — the engine's reason
VALIDATIONbuildableEnvelopeverticalCap + floorToFloor resolve to a non-finite or non-positive height (e.g. an extreme maxFloors × floorToFloor)verticalCap, floorToFloor
HANDLE_INVALIDbuildableEnvelopebuildableEnvelopeId does not resolve to an envelope on the canvas—
OPERATION_FAILEDbuildableEnvelopeThe in-place rebuild failed — typically the setbacks leave no buildable footprint on the site polygonwarnings, handles

spaces validates every item before anything is applied, so one bad item rejects the whole call with no partial updates (all-or-nothing) — the same guarantee space gets as a batch of one.