Skip to main content

Putaway policy, steps and conditions

This file lists every setting of a putaway policy. It covers the policy header, every step field, and every condition (criterion). Read 00-putaway-overview.md first. It explains the order in which the system works.

Zone settings are in 02-putaway-zone-settings.md. Location settings are in 03-location-settings.md.

How to read this file​

  • Menu path to the screen: Sidebar > Policy > Putaway Policy. Open a policy row to get the step editor.
  • Paths to code start at crates/libs/ unless they start with crates/services/.
  • BASELINE means crates/libs/wms-lib-sql/sql/wms-app/migrations/001_baseline.sql.
  • A line like step.rs:184 means wms-inventory/src/putaway/step.rs, line 184.
  • "Stored only. It has no effect today." means: I searched all crates and no code reads the field.
  • Units: the database stores weight in grams, length in millimetres and volume in cubic millimetres. The screens may show other units (for example kg). This is set per warehouse (enterprise.warehouse).
  • Roles: Admin, Manager and Supervisor can create, edit and delete policies and steps. Operator and Viewer can read them. The dry run is for Admin, Manager and Supervisor only (crates/services/app-server/src/web/rpcs/putaway_policy_rpc.rs:69-93).

Contents​

  1. Policy header (2 settings)
  2. Step fields (17 settings, plus 3 system fields)
  3. Conditions (16 properties, plus the rule, the values and the attribute code)
  4. Messages you can see
  5. The "never runs" mark
  6. The dry run

1. Policy header​

Screen: Sidebar > Policy > Putaway Policy. The list has the columns Code and Description. The header form is putaway_policy_normal_form (fields ID, Code, Description). The table is putaway_policy (BASELINE:3990).

1.1 Code​

ItemValue
UI labelCode (required). Menu: Sidebar > Policy > Putaway Policy.
Columnputaway_policy.code
Type and valuesText, up to 10 characters. Must be unique in the warehouse (putaway_policy_code_key, BASELINE:11351).
DefaultNo default. Seed: one policy, STD (id 1), with no steps (BASELINE:8608).
What it doesIt is the name of the policy. The code is the only key people use.
AffectsThe policy list. The SKU form (Putaway Policy, tab Policies) and the owner form (Putaway Policy) pick a policy by code.
ExamplePAL-FIFO (8 characters). PALLET-FIFO-2 is refused: 13 characters.
Interacts withA policy can be chosen on a SKU and as an owner default. The SKU wins (see 00-putaway-overview.md).
When emptyA new policy needs a code. Empty or spaces only is refused: putaway policy code cannot be empty (wms-lib-core/src/model/policies/putaway_policy.rs, create_pipeline).
If you change itYou cannot change it. The code is read-only after creation. The public update command has no code field (putaway_policy_rpc.rs:166, struct PutawayPolicyHeaderUpdate).

1.2 Description​

ItemValue
UI labelDescription.
Columnputaway_policy.description
Type and valuesText, up to 60 characters. Can be empty (NULL).
DefaultNULL. Seed: NULL for STD.
What it doesA free note about what the policy is for.
AffectsThe policy list only. No engine code reads it. Stored for people.
ExamplePallets, FIFO, no lot mixing.
Interacts withNothing.
When emptyAllowed. An empty description is saved as NULL.
If you change itThe change is saved at once. It uses the policy version check (see below). Nothing else changes.

1.3 System fields of the header​

FieldColumnMeaning
IDputaway_policy.idRow number. Read-only.
(hidden) Versionputaway_policy.version, default 1Lock number. The update command needs the version you read. If someone saved first, you get a version conflict (return code 40) and must reload. A reorder of steps also moves this number (reorder.rs).
(hidden)add_who, add_when, mod_who, mod_whenAudit stamps.

1.4 What happens when you delete a policy​

  • Deleting a policy deletes all its steps and all their conditions in one transaction.
  • It is refused while any SKU or any owner default points at it.
  • Message (exact form): Cannot delete: still in use by 2 items (SKU-A, SKU-B) and 1 owner (ACME) as their default. Point them somewhere else first. The message names up to 3 codes. It counts up to 50 (50+ items).
  • Code: wms-inventory/src/putaway/pipeline/delete_policy.rs:97-117.
  • Pallets that already have a reservation keep it. The reservation does not point at the policy.
SettingScreenColumnRule
Putaway PolicySKU, tab Policiessku.putaway_policy_idWins over the owner default. Empty = use the owner default.
Putaway PolicyOwner, WH Settings (owner_wh_policies_form)owner_config.default_putaway_policy_idUsed when the SKU has none. Empty = no default.

The rule is COALESCE(sku.putaway_policy_id, owner_config.default_putaway_policy_id) (wms-lib-core/src/model/sku.rs:867-885). A pallet with SKUs from different policies is refused (see section 4.1).


2. Step fields​

A step is one rule of the policy. The system tries the steps in order of sequence. The first step that finds a location wins. The editor shows a step as three bands: Destination, Conditions, Placement. The table is putaway_policy_detail (BASELINE:4009).

A new step is live at once. It is added at the end. Message: A new step is live at once and is tried after every rule above it. A new step takes the column defaults: Suitable, Zone from the SKU, no guard, no conditions. That step already works as a very wide rule (pipeline/add.rs).

2.0 System fields of a step​

FieldColumnType and defaultMeaning
Step numberstep_numText, up to 5 characters. Unique in the policy.Label shown as Step N (S): N is the position, S is this number. The system gives it when you add the step. It is the spelling of the sequence (10, 20, 30...). You cannot change it. Sending one is refused: Putaway step {id}: a step's number is assigned when the step is added and never ... (wms-lib-core/src/model/policies/putaway_policy_detail.rs:1000).
OrdersequenceWhole number, default 0. Unique in the policy.The order of work. A new step gets the highest sequence + 10. Only the drag-and-drop reorder changes it (reorder.rs). The steps are read by sequence, never by step_num (step_num '10' sorts before '2').
(hidden) VersionversionWhole number, default 1.Each step has its own lock number. Save and delete need the version you read. Two people can edit two different steps at the same time.

2.1 Mode​

ItemValue
UI labelMode. Band Destination.
Columnputaway_policy_detail.mode (enum putaway_mode)
Type and valuesSuitable or Consolidate.
DefaultSchema default Suitable. No steps are seeded in production. Dev seed uses Suitable (dev_only/install-db/900-dev-seed.sql:1026).
What it doesSuitable: any location that passes all checks. Consolidate: only a location that already holds (or has a reservation for) at least one product of the pallet. A product is one pair owner + SKU. The lot does not count here.
AffectsPutawayCtx.consolidate (putaway/mod.rs:928) and the rule ConsolidateRule (predicate.rs:767-848). It is the 2nd check on each candidate.
ExamplePallet of SKU W1. Location A-01-0 holds 5 cartons of W1. Location A-01-1 is empty. A Consolidate step offers A-01-0 and refuses A-01-1 with code not_consolidatable and the detail location holds nothing (no stock, no inbound reservation) — a Consolidate step requires the sku to already be there.
Interacts withMust be empty cannot be used with Consolidate (see 2.9). The mixing rules still apply on top: Consolidate plus Mixed SKU = Not allowed means "the same SKU only, and it must already be there". A location with a reservation for the same product counts as holding it.
When emptyNot possible. The column is NOT NULL.
If you change itTakes effect on the next suggestion. Existing reservations and stock do not change.

Values:

ValueMeaning
SuitableUI text Any location with room.
ConsolidateUI text A location already holding this item.

Note: a pallet that stands in a location can match itself under Consolidate (predicate.rs:754-763). The engine does not skip the source location. Moving to the same place costs nothing.

2.2 Scope (where to look)​

ItemValue
UI labelFive options in band Destination (no single label).
Columnputaway_policy_detail.scope (enum putaway_scope)
Type and valuesZoneFromSku, ZoneFromStep, LocationFromStep, LocationFromSku, AssignedSlot.
DefaultZoneFromSku.
What it doesIt says which zone, or which single location, the step searches.
Affectsstep::resolve_search_space (step.rs:517-564), called at putaway/mod.rs:956.
ExampleZone named on this step = BULK. Every candidate is a location of zone BULK.
Interacts withNeeds an anchor for two values (Zone or Location below). Database CHECK chk_putaway_step_scope_params (BASELINE:4039).
When emptyNot possible. NOT NULL.
If you change itNext suggestion only. An anchor left from an old scope stays in the row and is ignored (inert).

Values:

ValueUI textMeaningWorks today?
ZoneFromSkuZone from the SKUSearch the zone in sku.putawayzone of the first line of the pallet.Yes. If the SKU has no zone, the step is skipped (skipped:no-zone).
ZoneFromStepZone named on this stepSearch the zone named in Zone (to_zone).Yes.
LocationFromStepLocation named on this stepSearch only the location named in Location (to_location).Yes.
LocationFromSkuLocation from the SKUSearch only sku.putaway_loc of the first line.Yes. If the SKU has no location, the step is skipped (skipped:no-location). Most SKUs have none.
AssignedSlotPick location of the SKUSearch the SKU's pick locations (SKU card, tab Pick Locations), in route order.Yes. See below.

AssignedSlot — into the SKU's pick location:

  • The candidates are the SKU's pick locations, in route order (aisle, bay, level, code). Each one goes through the same checks as any candidate: blocked locations, the step's conditions, mixing, cube and weight, the reservation. The first that passes is reserved.
  • The pick location's Max is always checked, with no switch: what of this SKU the location holds and is promised, plus the pallet, may not exceed Max (in the unit of the pick location). Cube and weight are checked as well; the stricter limit wins. A pallet that does not fit is not split — the next pick location, then the next step, is tried. The trace counts it as slot_max_qty.
  • To choose a kind of pick location, add the condition Location type: for example Location type is Case for the case pick location.
  • A pallet of several SKUs skips the step (skipped:mixed-pallet): it has no one pick location.
  • A SKU with no pick location skips the step (skipped:no-slot).
  • Typical use, with the condition Pallet fullness (section 3): step 1 AssignedSlot + Pallet fullness is Partial (a part pallet goes straight to picking), step 2 a zone step (the rest goes to storage).

Known gap (step.rs:496-516): for a mixed pallet, ZoneFromSku and LocationFromSku use the first line only. If two SKUs name two zones, the second SKU goes to the first SKU's zone. The dry run and the trace record this (zone_downgrade, location_downgrade).

2.3 Zone (anchor of Zone named on this step)​

ItemValue
UI labelZone (placeholder Choose a zone…).
Columnputaway_policy_detail.to_zone
Type and valuesText, up to 20 characters. Must be an existing zone code (FK fk_putaway_step_to_zone, RESTRICT). NULL allowed.
DefaultNULL.
What it doesThe zone to search when the scope is ZoneFromStep.
Affectsstep.rs:529. Also zone_suits_temperature when Temperature is on.
ExampleBULK.
Interacts withOnly read when the scope is ZoneFromStep. For other scopes the value is ignored.
When emptyWith ZoneFromStep, save is refused: zone not chosen (database: Putaway step (policy P, sequence S) has scope 'ZoneFromStep' but no to_zone — that scope needs its parameter).
If you change itNext suggestion only. You cannot delete a zone that a step names (RESTRICT).

2.4 Location (anchor of Location named on this step)​

ItemValue
UI labelLocation (placeholder Choose a location…).
Columnputaway_policy_detail.to_location
Type and valuesText, up to 20 characters. Existing location code (FK fk_putaway_step_to_location, RESTRICT). NULL allowed.
DefaultNULL.
What it doesThe single location to search when the scope is LocationFromStep.
Affectsstep.rs:545, candidates.rs:594 (single_location).
ExampleA-01-0.
Interacts withThe location must still pass the status, flag and type gates (see 3.x and file 03-location-settings.md). A location that is on hold gives zero candidates.
When emptyWith LocationFromStep save is refused: location not chosen.
If you change itNext suggestion only.

2.5 Guard​

ItemValue
UI labelGuard (hint: hard limit on how far stock may travel).
Columnputaway_policy_detail.guard (enum putaway_guard)
Type and valuesNone, FromZone, FromLocation.
DefaultNone.
What it doesIt says for which pallets the step applies at all, based on where the pallet stands now. If the guard does not match, the step is skipped. It is not a failure.
Affectsstep::guard_allows (step.rs:382-388) at putaway/mod.rs:936. Trace status skipped:guard.
ExampleGuard Stay in the source zone with source zone QC. A pallet standing in QC-01 uses the step. A pallet standing in DOCK skips it.
Interacts withNeeds an anchor for two values (CHECK chk_putaway_step_guard_params, BASELINE:4036). The guard column compares only the current location or its zone. A NULL anchor never matches (it is treated as "applies to nothing", not "applies to all").
When emptyNot possible. NOT NULL.
If you change itNext suggestion only.

Values:

ValueUI textMeaning
NoneNo guard (Always)The step applies to any pallet.
FromZoneStay in the source zoneThe step applies only if the zone of the pallet's current location equals from_zone.
FromLocationStay in the source locationThe step applies only if the pallet's current location equals from_location.

The words in the screen ("Stay in...") say "stay". The code does not keep the stock in that zone. It only decides if the step runs. Do not read it as a travel limit on the destination.

2.6 Source zone and source location (anchors of the guard)​

ItemValue
UI labelZone and Location (shown under the guard option).
Columnputaway_policy_detail.from_zone, putaway_policy_detail.from_location
Type and valuesText, up to 20 characters. Existing zone or location code (FK RESTRICT). NULL allowed.
DefaultNULL.
What it doesThe value the pallet's current zone or location is compared with.
Affectsstep.rs:385-386.
Examplefrom_zone = RECV: the step runs only for pallets standing in zone RECV.
Interacts withOnly read when the guard is FromZone (zone) or FromLocation (location).
When emptyWith the guard FromZone: source zone not chosen. With FromLocation: source location not chosen.
If you change itNext suggestion only.

2.7 Ordering​

ItemValue
UI labelOrdering (hint: which eligible location is offered first).
Columnputaway_policy_detail.ordering (enum putaway_ordering)
Type and valuesRoute or NearestToSlot.
DefaultRoute.
What it doesIt sets the order in which candidate locations are tried. The first one that passes all checks is taken.
Affectscandidates::order_for (candidates.rs:48-58), SQL ORDER BY in wms-lib-core/src/model/location.rs:418-423.
ExampleLocations A-01-0, A-01-1, A-02-0. Route order tries A-01-0 first, then A-01-1, then A-02-0.
Interacts withA zone is not walked to the end. The system looks at at most 5 batches of 20 locations = 100 candidates per step (candidates.rs:28-32). After that the step gives up and the next step runs.
When emptyNot possible. NOT NULL.
If you change itNext suggestion only.

Values:

ValueUI textWhat the code does
RoutePick route (code list text: Walking order (aisle, bay, level))Sorts by aisle, then bay, then level, then code. It does not use Route Sequence. aisle is text, so aisle A10 sorts before A2. bay and level are numbers (level 0, the floor, first).
NearestToSlotNearest to the pick locationSorts the zone's locations by straight-line distance (x, y, z coordinates) to the SKU's first pick location in route order, then by code. Only for a zone scope (Zone from the SKU, Zone named on this step); on any other scope Save is refused: ordering by nearness to the pick location works only when the step searches a zone. The step is skipped when the pallet carries several SKUs (skipped:mixed-pallet), when the SKU has no pick location (skipped:no-slot), and when that pick location has coordinates 0, 0, 0 — never measured (skipped:slot-not-measured). It never falls back to route order.

Note: the caption Pick route may look like it uses the location setting Route Sequence. It does not. Route Sequence is used by allocation, pick routes and task claim order. See 03-location-settings.md.

2.8 Location occupancy (one choice, three columns)​

ItemValue
UI labelLocation occupancy (hint: what the location may already hold). Three options: Any occupancy, Must be empty, Allow mixing, with rules.
Columnsallow_mixed_sku, allow_mixed_lot, require_empty (all boolean, nullable)
Type and valuesThe screen writes the three columns from one choice (wms-lib-core/src/model/policies/putaway_occupancy.rs). See the table below.
DefaultColumn defaults: allow_mixed_sku = true, allow_mixed_lot = true, require_empty = false (BASELINE:4026-4028). This means "no opinion".
What it doesIt adds a step rule about what may already be in the location, on top of the location's own flags.
AffectsMixCheck::from_toggles (predicate.rs:129-142) at putaway/mod.rs:920. Check MixIntentRule (predicate.rs:451-651) is the 1st check on each candidate.
ExampleSee the three options below.
Interacts withSee 2.9, 2.10, 2.11 and the location flags Mix SKU and Mix Lot in 03-location-settings.md. A step can only narrow. It can never allow a mix the location forbids.
When emptyNULL, TRUE and "not set" all mean "no opinion" (MixCheck::None). The old NULL state was filled by migration 290.
If you change itNext suggestion only. Stock and reservations do not change.

What each option writes:

Optionrequire_emptyallow_mixed_skuallow_mixed_lotEngine rule (MixCheck)
Any occupancyNULLNULLNULLNone: no step rule. Only the location flags and lot rules decide.
Must be emptytrueNULLNULLRequireEmpty
Allow mixing, with rulesNULLas chosenas chosenNone, SameSku or SameSkuLot

Note: Allow mixing, with rules with both rows at Any writes the same three NULLs as Any occupancy. After you reopen the step it reads back as Any occupancy.

2.9 Must be empty (require_empty)​

ItemValue
UI labelMust be empty (hint: mixing rules do not apply and are not shown).
Columnputaway_policy_detail.require_empty
Type and valuestrue, false or NULL. Only true has a meaning.
Defaultfalse (schema).
What it doesThe location must hold no stock and no container, and no other pallet may have an active reservation for it.
AffectsMixIntentRule::require_empty (predicate.rs:602-650). Uses LocBmc::is_location_occupied (location.rs:2770): stock with qty, qty_allocated or qty_picked above zero, or any container not disposed, makes the location occupied. An empty pallet still occupies.
ExampleLocation C-01-0 holds an empty pallet LPN. It is not empty. Code mix_intent, detail step requires an empty location; occupied=true, inbound_reservations=0.
Interacts withCannot be combined with Mixed SKU = Not allowed or Mixed lot = Not allowed (database CHECK chk_putaway_step_require_empty_no_mixing). Cannot be combined with Mode = Consolidate. The pallet's own reservation does not count against the location.
When emptySee 2.8.
If you change itNext suggestion only.

Refusals:

  • Save: a location that must be empty has no mixing rules.
  • Save (mode): consolidating needs a location that already holds the stock, never an empty one.
  • The editor hides Must be empty on a Consolidate step and says: Consolidate places onto a location that already holds this SKU, so it can never be an empty one.
  • Engine (old rows): step sets mode=Consolidate together with require_empty=true: Consolidate requires the location to already hold one of the pallet's (owner, sku) identities ... so this step can never place a pallet.
  • Rows saved before 2026-09-12 may still have this pair. The engine then refuses the whole policy when it loads it.

2.10 Mixed SKU (allow_mixed_sku)​

ItemValue
UI labelMixed SKU with the choices Any, Allowed, Not allowed. Shown only under Allow mixing, with rules.
Columnputaway_policy_detail.allow_mixed_sku
Type and valuesNULL (Any), true (Allowed), false (Not allowed).
Defaulttrue.
What it doesOnly false has an effect. Not allowed means: after the pallet lands, the location may hold only one product (owner + SKU).
AffectsMixIntentRule::same_key (predicate.rs:534-598).
ExampleLocation S-01 holds SKU A. Pallet has SKU B. Result: refused with code mix_intent_sku and the detail step allows no mixing beyond the same sku; location plus pallet would span 2 identities: owner 1/sku A, owner 1/sku B.
Interacts withThe "committed" stock of a location = present stock plus the contents of every pallet with an active reservation for it (inventory_balances.rs:1718-1750). A pallet with two SKUs fails at every location, even an empty one (the pallet alone makes 2 identities). Same SKU code under another owner counts as a different product.
When emptyAny/NULL/true: no step rule.
If you change itNext suggestion only. Existing stock stays as it is, even if it is mixed.

2.11 Mixed lot (allow_mixed_lot)​

ItemValue
UI labelMixed lot with the choices Any, Allowed, Not allowed. Shown only after Mixed SKU is decided.
Columnputaway_policy_detail.allow_mixed_lot
Type and valuesNULL, true, false.
Defaulttrue.
What it doesNot allowed (and Mixed SKU = Not allowed) means one SKU and one lot per location.
AffectsMixIntentRule::same_key with the lot compared (predicate.rs:469-472). Code mix_intent_sku_lot.
ExampleLocation holds SKU A lot L1. Pallet has SKU A lot L2. Refused with step allows no mixing beyond the same sku and lot; location plus pallet would span 2 identities: owner 1/sku A/lot L1, owner 1/sku A/lot L2.
Interacts withNot allowed is only valid when Mixed SKU is also Not allowed (CHECK chk_putaway_step_mixing_executable, BASELINE:4037). The engine cannot express "one lot across several SKUs". With Mixed SKU = Not allowed and Mixed lot = Allowed, the rule is "one SKU, lots may differ".
When emptyNULL/true: lots may differ.
If you change itNext suggestion only.

Refusals:

  • Save: one lot per location needs one SKU per location.
  • Screen hints: decide Mixed SKU first — mixed lot has no meaning until then; one lot never spans several SKUs — with mixed SKUs allowed, lots cannot be kept apart.
  • Engine (old rows): step sets allow_mixed_lot=Some(false) with allow_mixed_sku=...: it asks for ONE LOT per location while permitting SEVERAL SKUs, and the engine has no such rule ... (step.rs:32-43).

Offered choices:

Mixed SKUMixed lot choices
Anynone (greyed)
AllowedAny, Allowed
Not allowedAny, Allowed, Not allowed

2.12 Temperature (respect_temperature)​

ItemValue
UI labelTemperature (hint: a rule about the zone, not about the load). The switch reads The zone's temperature range must cover the SKU's.
Columnputaway_policy_detail.respect_temperature
Type and valuestrue or false.
Defaultfalse.
What it doesWhen on, the step is skipped if the zone it searches does not suit the temperature of every line on the pallet.
Affectsstep::zone_suits_temperature (step.rs:438-469) at putaway/mod.rs:1014 (zone scope) and :1197 (location scope). Trace status skipped:temperature.
ExampleZone COLD: min 2, max 8. SKU: min 0, max 4. They overlap (2..4), so the step runs. SKU: min 10, max 20: no overlap, so the step is skipped.
Interacts withReads the zone columns min_temperature and max_temperature (02-putaway-zone-settings.md) and the SKU columns min_temperature and max_temperature. An empty bound means "no limit" on that side, for both the zone and the SKU. If all lines fit, the step runs; one bad line skips it. A line whose SKU did not load counts as fitting.
When emptyNot possible (NOT NULL).
If you change itNext suggestion only.

Important: the test is overlap, not "cover". The check is zone_min <= sku_max && sku_min <= zone_max (step.rs:458-469). The screen label says "must cover" and the readback sentence says The location's temperature range must cover the SKU's. Both words are stronger than the code and both say "location" where the code reads the zone. The dry run says "suit" (dry_run.rs:769-773), which is correct.

2.13 Fit checks (five switches)​

The Fit checks row has five switches (hint: refuse a candidate that cannot physically take it). Each switch is one column. They are independent. The code reads all five together (FitToggles, space.rs:496-549). The checks run on each candidate as the 3rd check, rule CapacityRule (predicate.rs:285-425).

Common rules for all five:

  • A limit of 0 or NULL means "no limit set". The check is not run, and the location is still offered. The system counts it in the trace as checks not run with the key <limit>:no_limit (space.rs:1156-1195). So an empty capacity does not block putaway, and does not protect the location either.
  • The system counts stock already there plus space promised by active reservations (not yet arrived). The pallet's own reservation is not counted twice.
  • If the pallet already stands in the candidate location, the check is skipped (space.rs:670).
  • Oversize goods and held sections are refused before these switches, whatever you set (see 2.14).
  • Important: a cube or weight limit set on the location or the zone is always enforced, whatever the switches say. The move itself (move_execute) checks location and zone cube and weight, and the zone case count, on every move (wms-inventory/src/movement/validation.rs:920-1005), so putaway checks them too and never offers a location the move would refuse (P-18). The Cube and Weight switches only decide whether a cube or weight check that could not be made (no limit set, or the pallet has no known weight) is reported in the trace. Pallet dimensions, Stacking limit and Quantity are switched on and off as before, and are not checked by the move at all.

2.13.1 Cube (fit_by_cube)​

ItemValue
UI labelCube.
Columnputaway_policy_detail.fit_by_cube
Type and valuestrue or false.
Defaulttrue.
What it doesAdds the pallet's volume to what is in the location and compares with location.max_cube_capacity. If the pallet goes to another zone, it also checks putawayzone.max_cube.
Affectsspace.rs:749-776 (location) and :835-840 (zone). Refusal code capacity, detail loc_cube: limit L, attempted A or zone_cube: ....
ExampleLocation limit 4,500,000,000 mm³ (4.5 m³). Held 3,000,000,000 + promised 0. Pallet 1,800,000,000. Attempted 4,800,000,000 is above the limit. Refused: loc_cube: limit 4500000000, attempted 4800000000.
Interacts withThe pallet volume is the sum of sku.cube × quantity over its lines. A SKU with cube 0 adds 0. Then the check cannot refuse a new pallet. The zone check runs only if the destination zone differs from the zone where the pallet stands.
When emptyA limit set on the location or zone is enforced even with the switch off. Limit 0 = no limit; with the switch on it is reported as loc_cube:no_limit, with it off it is not reported.
If you change itNext suggestion only.

2.13.2 Weight (fit_by_weight)​

ItemValue
UI labelWeight.
Columnputaway_policy_detail.fit_by_weight
Type and valuestrue or false.
Defaulttrue.
What it doesCompares pallet weight + weight in the location + promised weight with location.max_weight_capacity (and putawayzone.max_weight for another zone).
Affectsspace.rs:749-768, :829-834. Detail loc_weight: limit L, attempted A.
ExampleLocation A-02-3 limit 400,000 g (400 kg). Pallet 720,000 g. Refused: loc_weight: limit 400000, attempted 720000.
Interacts withThe weight uses one formula for all code (StockWeights). If the pallet has no known weight, the check is not run. The trace key is loc_weight:no_stock_weight. Fix it on the item or pack, not on the location.
When emptyA limit set on the location or zone is enforced even with the switch off. The switch only decides whether no_limit / no_stock_weight is reported.
If you change itNext suggestion only.

2.13.3 Pallet dimensions (fit_by_pallet_dims)​

ItemValue
UI labelPallet dimensions.
Columnputaway_policy_detail.fit_by_pallet_dims
Type and valuestrue or false.
Defaultfalse.
What it doesChecks that the pallet's footprint (length × width of the wooden base) fits the location's length × width, in either direction. Also checks the pallet's height against the location height.
Affectsspace.rs:684-692, check_pallet_dims (space.rs:875-918). Details: loc_footprint: location 1200 × 800, pallet 1300 × 1100 (checked both orientations) and loc_height: location 1500, pallet 1800.
ExampleLocation 2500 × 1200 mm, height 1500. Pallet base 1200 × 800, height 1650 (base 150 + 3 layers × 500). Footprint fits. Height 1650 is above 1500: refused.
Interacts withPallet size comes from the pack: pallet_wood_length, pallet_wood_width, pallet_wood_height, pallet_hi and the height of the stacked unit. If the pack does not describe the pallet, the check is not run: loc_footprint:no_product_dims or loc_height:no_product_dims. If the location has no length/width/height (0), the trace says no_location_dims. A pallet exactly as tall as the location fits (> not >=).
When emptySee above.
If you change itNext suggestion only. Switching it on changes which locations an unchanged policy chooses.

2.13.4 Stacking limit (fit_by_stack_limit)​

ItemValue
UI labelStacking limit.
Columnputaway_policy_detail.fit_by_stack_limit
Type and valuestrue or false.
Defaultfalse.
What it doesCounts pallet positions. The capacity is location.footprint × stack limit. The pallets standing plus the pallets promised plus this one must not exceed it.
Affectsspace.rs:704-727. Details: loc_positions: limit L, attempted A (the rack limit decides) or item_positions: ... (the item's own Stack limit is lower than the rack's).
ExampleLocation footprint 2, stack limit 3: 6 positions. 5 pallets standing or promised. This one is the 6th: fits. The next one: loc_positions: limit 6, attempted 7.
Interacts withStack limit = the lower of the rack (location.stack_limit) and the item (sku.stack_limit), when each is above 0. An item may lower the rack's limit, never raise it. Location Pallet positions on floor = 0 gives limit 0, reported as loc_positions:no_limit.
When emptySwitch off = not checked.
If you change itNext suggestion only. The move does not check this limit.

2.13.5 Quantity (fit_by_quantity)​

ItemValue
UI labelQuantity.
Columnputaway_policy_detail.fit_by_quantity
Type and valuestrue or false.
Defaultfalse.
What it doesCompares the quantity already in the location plus the quantity arriving with location.max_qty_capacity. This is how a pick face is sized.
Affectsspace.rs:732-742. Detail loc_qty: limit L, attempted A.
ExamplePick face limit 500 pieces. Holds 380. Pallet brings 150. Attempted 530. Refused: loc_qty: limit 500, attempted 530.
Interacts withThe quantity is a plain sum of all balance lines in stored units. The location limit is Max quantity on the Dimensions tab. 0 = not configured: reported, not refused.
When emptySwitch off = not checked.
If you change itNext suggestion only. The move does not check this limit.

2.14 Checks you cannot switch off​

These run on every candidate whatever the step says:

  • Oversize goods (sku.positions_required above 1) need a whole free section of positions. Refusal codes: section_none (location is in no section), section_not_free, section_too_small. Detail: needs N adjacent positions of one free section (space.rs:1052-1089, predicate.rs:312-340).
  • A location held for another pallet's oversize goods: code section_promised, detail held for goods spanning this section (predicate.rs:346-351).
  • The zone case count (putawayzone.max_cases_count) when the pallet goes to another zone (space.rs:794-821).
  • The location landing rules (the 4th check): see 03-location-settings.md.

2.15 What the readback sentence says​

The step card shows a sentence, for example: Takes locations of type Case or Pick, class A, ... in zone BULK. One SKU per location. Checks volume and weight. Candidates in warehouse route order. Two gaps (found in code, putaway_step_describe.rs:1047-1066):

  • The sentence names only volume, weight and pallet dimensions. Stacking limit and Quantity are never named. If only those two are on, the sentence still says Checks nothing physical — the pallet's size and weight are not compared with the location's capacity.
  • The temperature sentence says "location" and "cover" (see 2.12).

3. Conditions (criteria)​

A condition narrows a step. Table putaway_step_criterion (BASELINE:4130). In the editor, band Conditions, button Add condition (a three-question picker: Choose a property, Choose an attribute, Choose values; button Save condition). The band shows N of 16 properties used.

3.1 Two kinds of condition​

KindFamily headingSubject (column)What it decides
About the palletProduct and LotProductDoes the step apply to this pallet at all? If any line of the pallet fails any condition, the whole step is skipped (trace skipped:product:<Property>).
About the locationLocationLocationWhich locations of the search space are candidates? Other locations are never looked at.

The subject follows from the property. You do not choose it (CriterionProperty::subject, putaway_step_criterion.rs:108-128).

3.2 The columns every condition has​

FieldColumnType and valuesRules
Rulerule (enum putaway_criterion_rule)Include (UI is), Exclude (UI is not)One rule per property per step. You cannot have is and is not on one property in one step.
Valuesvalues (text array)At least one value (CHECK chk_step_criterion_values_nonempty). Values are joined by or.Compare exact and case-sensitive. For is: the value must be one of the list. For is not: the value must not be in the list.
Attribute codeattribute_code (text, up to 50)Required for the 3 attribute properties. Must be empty for all other properties (CHECK chk_step_criterion_attribute_code).One condition per property and attribute code. COLOR and SIZE are two conditions.
SubjectsubjectProduct or LocationSet by the system.

Uniqueness: uq_step_criterion_property on (step, subject, property, attribute code) (BASELINE:14371). Defaults: no condition exists by default. No condition is seeded.

For all conditions:

  • A step with no conditions says: No conditions. Every location in scope is eligible — this step matches almost everything, so it belongs near the end of the pipeline.
  • When you save, the values are checked. Closed lists (enums) accept only their own labels (see each property). Free-text values (group, class, attributes) are never checked against existing data, because a policy is often written before the items exist.
  • Changing a property without sending new values is refused (see 4.4).
  • Deleting a step deletes its conditions (FK CASCADE).
  • Changing a condition affects the next suggestion only.

3.3 Summary of the 16 properties​

#UI labelCodeFamilyReadsValues
1Location typeLocationTypeLocationlocation.loc_typeenum loc_type (18 values; only 6 can be used)
2Location statusLocationStatusLocationlocation.statusOk, Hold, Damage (narrow-only)
3Location categoryLocationCategoryLocationlocation.loc_category17 values
4Processing typeLocationProcessingTypeLocationlocation.loc_processing_typeNone, Pallet, Case, Piece
5Location flagLocationFlagLocationlocation.loc_flag5 values (narrow-only)
6Location ABCLocationAbcLocationlocation.abcA, B, C
7Mixed SKUMixSkuLocationlocation.mix_skutrue, false
8Mixed lotMixLotLocationlocation.mix_lottrue, false
9SKU ABCSkuAbcProductsku.abcA, B, C
10SKU groupSkuGroupProductsku.sku_groupfree text
11SKU classSkuClassProductsku.classfree text
12Putaway classPutawayClassProductsku.putaway_classNone, NoMix
13RotationRotationProductsku.rotationFifo, Lifo, Fefo
14Lot attributeLotAttributeLotlot_attributes.attribute_valuefree text, needs a code
15SKU attributeSkuAttributeProductattribute_value.value_text for entity_type = 'sku'free text, needs a code
16Location attributeLocationAttributeLocationattribute_value.value_text for entity_type = 'location'free text, needs a code
17Pallet fullnessPalletFullnessProductcomputed from the pallet and its packFull, Partial

Code: candidates.rs:400-543 (location side), product.rs:207-278 (product side), step.rs:325-362 (gate).

A property whose stored subject is the wrong one (for example Product + LocationType) is refused when the policy loads: step uses criterion=Product/LocationType, which this build cannot execute (step.rs:326-334). SkuAttribute or LocationAttribute without a code: step's Product/SkuAttribute criterion carries no attribute_code: ... (step.rs:105-110).

3.4 Location conditions​

Each narrows the candidate list in SQL (location.rs:1685-1925), so a refused location is never evaluated. The trace of a failed step (full detail) shows how many locations each property removed (criteria_removed).

All location candidates must also pass the fixed gate, whatever the conditions say: status = 'Ok', loc_flag = 'None', discard_lpn not true, and the type in the allowed set (location.rs:2140-2143).

3.4.1 Location type​

ItemValue
UI labelLocation type.
Column readlocation.loc_type.
Type and valuesLabels of enum loc_type: None, Other, Case, Pick, Pnd, Door, Pickto, Sort, SpeedPick, QC, Damage, Rtv, Destroy, Returns, Stage, Lost, InTransit, Pack. Other spellings are refused when saved.
DefaultNo condition. Without one, the step uses the authorized set: Case, Pick, SpeedPick, Pnd, Sort, Other (movement/validation.rs:135-148).
What it doesNarrows the types. A step may narrow the authorized set. It can never widen it. Types outside the set are dropped silently from is.
Affectscandidates.rs:107-177 and :400-445. SQL l.loc_type = ANY(...).
ExampleLocation type is Pick or Case: only pick faces and case locations. is Door: refused (see below).
Interacts withThe move validates the same set, so a suggestion is never refused for its type (DestinationNotAuthorizedForSourceType).
When emptyNo condition = the six authorized types.
If you change itNext suggestion only.

Refusals (when the policy loads, so the whole policy is refused):

  • is with only unauthorized types: Putaway step restricts locations to [Door], and a putaway may not land in any of them. Authorized types are [Case, Pick, SpeedPick, Pnd, Sort, Other].
  • is not that covers all six: Putaway step excludes locations [Case, Pick, SpeedPick, Pnd, Sort, Other], and a putaway may not land anywhere else. Authorized types are [Case, Pick, SpeedPick, Pnd, Sort, Other].
  • A value that is not a type: Putaway step criterion 12 (Location/LocationType Include) names value 'Mezzanine', which does not exist: <detail>. The criterion is refused rather than ignored — ignoring it would widen the search past what the policy author wrote. The same shape is used for every property below. It is prefixed by step <num> of policy <id>: (mod.rs:869-874).
  • At save: 'Mezzanine' is not a value a 'LocationType' criterion can match — every comparison the engine makes is exact and case-sensitive. 'LocationType' offers: 'None', 'Other', ... (putaway_step_criterion.rs:486-501).

3.4.2 Location status​

ItemValue
UI labelLocation status.
Column readlocation.status.
Type and valuesOk, Hold, Damage.
DefaultNo condition. The fixed gate already requires Ok.
What it doesNarrow-only. Every candidate already has status Ok. So the only useful forms are is Ok (redundant) and is not Hold (vacuous).
Affectscandidates.rs:300-354 (resolve_gated).
Exampleis Ok: accepted, adds no filter.
Interacts withYou cannot use it to reach a location on hold.
When emptyNo condition.
If you change itNext suggestion only.

Refusals (policy load): is with anything but only Ok: Putaway step criterion 7 (Location/LocationStatus Include) asks for [Hold], and a putaway may only ever land on a location whose LocationStatus is 'Ok' — the candidate query enforces that unconditionally, regardless of this criterion. Include 'Ok', or drop the criterion. is not Ok: ... excludes 'Ok', and a putaway may only ever land on a location whose LocationStatus is 'Ok' — the step can therefore match no location at all.

3.4.3 Location category​

ItemValue
UI labelLocation category.
Column readlocation.loc_category.
Type and valuesNone, NoPalletization, Asrs, CantileverRack, CartonFlow, DenseStorage, DoubleDeepRack, DriveInRack, DriveThroughRack, HorizontalCarousel, Other, PalletFlowRack, PalletCarousel, PushBackRack, SelectiveShelving, ShelvingStorage, WorkCenter.
DefaultNo condition.
What it doesKeeps only (or drops) locations of these storage equipment types.
Affectscandidates.rs:467-469.
ExampleLocation category is ShelvingStorage for small parts.
Interacts withSeed locations use SelectiveShelving.
When emptyNo condition.
If you change itNext suggestion only.

3.4.4 Processing type​

ItemValue
UI labelProcessing type.
Column readlocation.loc_processing_type.
Type and valuesNone, Pallet, Case, Piece.
DefaultNo condition.
What it doesKeeps locations handled by pallet, case or piece.
Affectscandidates.rs:470-472.
ExampleProcessing type is Pallet.
Interacts withNothing else reads this location field except this condition and the location generator.
When emptyNo condition.
If you change itNext suggestion only.

3.4.5 Location flag​

ItemValue
UI labelLocation flag.
Column readlocation.loc_flag.
Type and valuesNone, CycleCountActive, SanitationActive, MaintenanceActive, ReceivingHoldoff.
DefaultNo condition. The fixed gate requires None.
What it doesNarrow-only, same as the status. is None is redundant. Any other is is refused.
Affectscandidates.rs:464-466.
Exampleis None: accepted, no effect.
Interacts withA flagged location is never a candidate.
When emptyNo condition.
If you change itNext suggestion only.

Refusal text has the same shape as for the status: ... may only ever land on a location whose LocationFlag is 'None' ....

3.4.6 Location ABC​

ItemValue
UI labelLocation ABC.
Column readlocation.abc (default B).
Type and valuesA, B, C (enum abc_speed_type).
DefaultNo condition.
What it doesKeeps fast (A), medium (B) or slow (C) locations.
Affectscandidates.rs:473-475.
ExampleLocation ABC is A or B.
Interacts withPairs with SKU ABC to put fast items in fast locations.
When emptyNo condition.
If you change itNext suggestion only.

3.4.7 Mixed SKU (location flag)​

ItemValue
UI labelMixed SKU, in family Location. Do not confuse it with the step switch Mixed SKU (2.10).
Column readlocation.mix_sku.
Type and valuestrue, false.
DefaultNo condition.
What it doesKeeps locations whose flag Mix SKU is on (true) or off (false).
Affectscandidates.rs:476-478.
ExampleMixed SKU is false: only single-SKU locations.
Interacts withThe landing rule enforces the flag anyway (03-location-settings.md). This condition just avoids wasting candidates.
When emptyNo condition.
If you change itNext suggestion only.

Difference: the location flag looks at the location's setting. The step switch looks at what is in the location now.

3.4.8 Mixed lot (location flag)​

Same as 3.4.7 for location.mix_lot (UI label Mixed lot, code MixLot, candidates.rs:479-481).

3.4.9 Location attribute​

ItemValue
UI labelLocation attribute (also needs an attribute from Choose an attribute).
Column readattribute_value.value_text of the location, for attribute definitions with entity_type = 'location', type Text, active.
Type and valuesFree text values. The attribute code comes from Sidebar > Attributes definitions.
DefaultNo condition.
What it doesKeeps locations whose attribute value is (or is not) in the list.
Affectscandidates.rs:507-511, SQL EXISTS (location.rs:1860-1925).
ExampleLocation attribute HAZMAT is not FLAMMABLE.
Interacts withA location with no value for the code: is removes it; is not keeps it. Only Text definitions are offered.
When emptyNo condition.
If you change itNext suggestion only.

3.5 Product and lot conditions​

These are checked once per step, before any location is read (product.rs:343-370). The rule is any line fails = the step is skipped. The pallet is one unit.

How a missing value is read:

  • The five SKU-column properties (SKU ABC, SKU group, SKU class, Putaway class, Rotation): an empty SKU field does not refuse. A blank field is treated as "no opinion", so the step is not skipped. A line whose SKU did not load also does not refuse.
  • The two attribute properties (Lot attribute, SKU attribute): a missing value refuses. The step asked a question. "Nothing recorded" is the answer "no".

3.5.1 SKU ABC​

ItemValue
UI labelSKU ABC (SKU form: ABC Class).
Column readsku.abc (schema default B).
Type and valuesA, B, C.
DefaultNo condition.
What it doesThe step applies only to pallets whose SKUs have these classes.
Affectsproduct.rs:344-346. Trace skipped:product:SkuAbc.
ExampleStep 10 SKU ABC is A to zone FAST. A pallet with SKU class C skips step 10.
Interacts withsku.abc is NULL for no SKU created by default (the default is B).
When emptyNo condition.
If you change itNext suggestion only.

3.5.2 SKU group​

ItemValue
UI labelSKU group (SKU form: SKU Group).
Column readsku.sku_group (text, up to 10).
Type and valuesFree text. Case-sensitive. The picker offers the distinct groups now used by SKUs.
DefaultNo condition.
What it doesThe step applies only to SKUs of these groups.
Affectsproduct.rs:347-349.
ExampleSKU group is FROZEN. A SKU with group frozen does not match (case-sensitive).
Interacts withA group no SKU uses yet is accepted.
When emptyA SKU with no group does not refuse.
If you change itNext suggestion only.

3.5.3 SKU class​

ItemValue
UI labelSKU class (SKU form: Class).
Column readsku.class (text, up to 20).
Type and valuesFree text, case-sensitive.
DefaultNo condition.
What it doesSame as SKU group, for the Class field.
Affectsproduct.rs:350-352.
ExampleSKU class is HAZ.
Interacts withNone.
When emptyA SKU with no class does not refuse.
If you change itNext suggestion only.

3.5.4 Putaway class​

ItemValue
UI labelPutaway class (SKU form: Putaway Class).
Column readsku.putaway_class (default None).
Type and valuesNone, NoMix.
DefaultNo condition.
What it doesThe step applies only to SKUs with this class.
Affectsproduct.rs:353-355.
ExamplePutaway class is NoMix with Mixed SKU = Not allowed sends no-mix SKUs to single-SKU locations.
Interacts withNoMix on the SKU does nothing by itself. No code stops mixing because of it. A Putaway class condition (or a move rule, which is deferred: movement/validation.rs:8) is the only reader. Add the condition and the mixing switch yourself.
When emptyA SKU with an empty class does not refuse.
If you change itNext suggestion only.

3.5.5 Rotation​

ItemValue
UI labelRotation.
Column readsku.rotation (default Fifo).
Type and valuesFifo, Lifo, Fefo.
DefaultNo condition.
What it doesThe step applies only to SKUs with this rotation.
Affectsproduct.rs:356-358.
ExampleRotation is Fefo to send expiry-driven goods to a front-loaded zone.
Interacts withRotation also drives allocation. Putaway only reads it in this condition.
When emptyNo condition.
If you change itNext suggestion only.

3.5.5a Pallet fullness​

ItemValue
UI labelPallet fullness.
Column readNone — computed for each pallet: its quantity against the base quantity of the top level of its pack hierarchy (the same "full pallet" allocation uses).
Type and valuesFull — at least a full pallet (more than a full pallet is also Full); Partial — less, or several SKUs on the pallet.
DefaultNo condition.
What it doesThe step applies only to pallets of this fullness.
When it cannot be measuredThe pack has no level above its base unit: the step is skipped (skipped:product:PalletFullness), as for a lot attribute with no value.
ExamplePallet fullness is Partial on an AssignedSlot step: part pallets go straight to the pick location.
If you change itNext suggestion only.

3.5.6 Lot attribute​

ItemValue
UI labelLot attribute (family Lot). Needs an attribute from Choose an attribute.
Column readlot_attributes.attribute_value for (lot, attribute code). The codes offered are from the lot policies (lot_policy_attribute.attrib_code).
Type and valuesFree text, case-sensitive. The picker offers values recorded on lots now.
DefaultNo condition.
What it doesThe step applies only to pallets whose lots have these attribute values.
Affectsproduct.rs:359-363 and :442-457.
ExampleLot attribute ALLERGEN is YES. A pallet whose lot has no ALLERGEN value skips the step.
Interacts withA lot is found by lot code alone (not by owner). A lot with no recorded value refuses. One condition per code.
When emptyNo condition.
If you change itNext suggestion only.

3.5.7 SKU attribute​

ItemValue
UI labelSKU attribute. Needs a code.
Column readattribute_value.value_text for the SKU, definitions with entity_type = 'sku' (Text, active). Defined under Sidebar > Attributes.
Type and valuesFree text.
DefaultNo condition.
What it doesThe step applies only to SKUs whose attribute has these values.
Affectsproduct.rs:364-368 and :477-495.
ExampleSKU attribute COLOR is RED or BLUE.
Interacts withThe lot attribute COLOR and the SKU attribute COLOR are two different things. A SKU with no value refuses.
When emptyNo condition.
If you change itNext suggestion only.

4. Messages you can see​

4.1 Policy and pallet errors (the whole request fails)​

These are returned when the system cannot ask the question. They are not "no location".

MessageMeaning and fix
container N not foundThe pallet id is wrong.
container N holds no stock to put awayEmpty pallet.
container N has no current location to put away fromThe pallet has no position. Move it to a location first.
no putaway policy on the SKU or the owner defaultSet Putaway Policy on the SKU or the owner (1.5).
LPN spans SKUs with different putaway policies: SKU-A (owner 1, policy 10), SKU-B (owner 1, policy 20)Split the pallet or use one policy. A SKU with no policy is not counted.
step uses scope=AssignedSlot, which this build cannot executeChange the scope (2.2).
step uses ordering=NearestToSlot, which this build cannot executeChange the ordering (2.7).
step sets allow_mixed_lot=... with allow_mixed_sku=...See 2.11.
step sets require_empty=true together with allow_mixed_sku=... / allow_mixed_lot=...See 2.9.
step sets mode=Consolidate together with require_empty=true ...See 2.9.
step <num> of policy <id>: <message>A condition names a value that does not exist (3.4.1).
suggest_location requires an open transaction ...Programming error. Report to support.

Sources: policy.rs:19-41, step.rs:18-117, mod.rs:119-158.

4.2 Why a location is refused (rejection codes)​

In the dry run and the trace, a step shows Refused by: <code> on <count>, .... The code is the engine's own text. These are all the codes.

CodeCheckMeaningExact detail text (if any)
excludedrequestYou excluded this location (the operator refused it).
mix_intentoccupancyMust be empty and the location is not empty or has another pallet's reservation.step requires an empty location; occupied=true, inbound_reservations=1
mix_intent_skuoccupancyLocation plus pallet would hold more than one SKU.step allows no mixing beyond the same sku; location plus pallet would span 2 identities: owner 1/sku A, owner 1/sku B
mix_intent_sku_lotoccupancyMore than one SKU+lot.step allows no mixing beyond the same sku and lot; location plus pallet would span 2 identities: ...
not_consolidatablemodeConsolidate and the location holds none of the pallet's products.location holds nothing (no stock, no inbound reservation) — a Consolidate step requires the sku to already be there or step requires the location to already hold one of the pallet's (owner, sku) identities; location is committed to 1 other product(s): owner 1/sku B
capacityfitA limit is exceeded.loc_cube: limit L, attempted A, loc_weight: ..., loc_qty: ..., loc_positions: ..., item_positions: ..., zone_cube: ..., zone_weight: ..., zone_cases_count: ..., loc_footprint: location 1200 × 800, pallet 1300 × 1100 (checked both orientations), loc_height: location 1500, pallet 1800
section_nonefitOversize goods and the location has no Section.needs 3 adjacent positions of one free section
section_not_freefitSection too small or not wholly free.same
section_too_smallfitSection free but too small for the goods.same
section_promisedfitThe location is held for another pallet's oversize goods.held for goods spanning this section
location_not_foundfitThe location row vanished.location X not found
zone_not_foundfitThe zone row is missing.zone X not found
mix_skulandingThe location has Mix SKU off and another SKU is there.Location L does not allow SKU mixing (incoming sku B, existing ["A"])
mix_lotlandingThe location has Mix Lot off and another lot is there.Location L does not allow lot mixing (incoming lot Some("L2"), existing ["L1"])
mix_attributelandingA location or zone Lot Commingle rule refuses.attribute ALLERGEN=YES mixing not allowed for lot L2 on lpn Some("LPN1") [Some("putawayzone_lot_commingle rule on zone FOOD")]
lpn_multi_lotlandingThe pallet itself carries two lots of a SKU that does not allow that. Same answer at every location.LPN1 already holds lot L1 of A; another lot of the same SKU is not allowed on it
ambiguous_skulandingA SKU could not be resolved.ambiguous SKU resolution (...)
landing_configlandingBad data (location or SKU/owner missing).
landing_no_contentslandingEmpty pallet.LPN X has no contents to put away
under_lock:<kind>raceThe location passed, then failed when locked (another operator won). <kind> is one of the codes above.
location_goneraceThe location changed or was deleted meanwhile.
lock_timeoutraceAnother transaction held the location for more than 5 seconds (see 4.5).
pallet_already_reservedraceAnother request holds this pallet's reservation. The scan stops.

Codes that stop the whole request (database or system trouble, not a property of the location): landing_occupancy, section_lookup, mix_intent_system, consolidate_system, capacity_system, landing_system. The message is <code> while evaluating <location> for step <num> of policy <id>: <detail>.

Rare codes that the putaway path cannot reach today: lpn_owner_conflict, lpn_mix_sku.

Sources: predicate.rs:285-1017, mod.rs:657-778, wms-inventory/src/inventory_service.rs:999-1280, wms-inventory/src/error/commingle.rs.

4.3 Step status in the trace​

StatusMeaning
skipped:guardThe guard did not match where the pallet stands.
skipped:product:<Property>A pallet condition failed (the property is named).
skipped:no-zoneThe scope found no zone (Zone from the SKU and the SKU has none).
skipped:no-locationThe scope found no location.
skipped:temperatureThe zone does not suit the pallet's temperature.
evaluatedThe step searched and took nothing.
matchedThe step took a location.

"Offered without checking": when a switch is on but the limit or the measure is missing the trace counts <limit>:<reason>. Limits: loc_cube, loc_weight, loc_qty, loc_footprint, loc_height, loc_positions, zone_cube, zone_weight, zone_cases_count. Reasons: no_limit (set up the location or zone), no_product_dims (item or pack master data), no_location_dims (location length/width/height), no_stock_weight (item weight).

The dry run sentence for a step that took nothing reads: step 02 (20) ran over 12 candidate(s) and took none of them. Refused by: capacity on 7, mix_sku on 5. Offered without checking: loc_cube:no_limit on 5 — the limit or the measurement is missing. It stopped at its scan budget rather than at the end of the zone, so there may be locations it never looked at.

4.4 Messages when you save a step or a condition​

Step save (shown as cannot save — <reasons>):

  • zone not chosen, location not chosen, source zone not chosen, source location not chosen
  • one lot per location needs one SKU per location
  • a location that must be empty has no mixing rules
  • consolidating needs a location that already holds the stock, never an empty one

Database wording (API callers):

  • Putaway step (policy P, sequence S) has scope 'X' but no to_zone — that scope needs its parameter
  • Putaway step (policy P, sequence S) has guard 'X' but no from_zone — that guard needs its parameter
  • Duplicate putaway step sequence (policy P sequence S) — steps of one policy need explicit, unique sequence values ...

Condition save:

  • A 'LocationType' criterion narrows a column of its own, so it takes no attribute_code — but this one still carries 'COLOR', left over from an attribute property. Clear attribute_code, or pick the attribute property you meant.
  • A 'SkuAttribute' criterion must name WHICH attribute it narrows on; attribute_code is empty.
  • A 'LocationType' criterion with no values narrows the candidates to nothing, which reads in a trace exactly like an exhausted zone. Pick at least one value.
  • This criterion's values were picked for LocationType and the change moves it to LocationStatus, without saying what the new values are. ... Send the values for LocationStatus as well.
  • 'Mezzanine' is not a value a 'LocationType' criterion can match — every comparison the engine makes is exact and case-sensitive. 'LocationType' offers: ...

Whole save (all steps at once):

  • putaway step 1012: condition 55 does not belong to this step
  • putaway step 1012: SkuAttribute 'COLOR' carries more than one condition in this set — a step may narrow each property once
  • putaway policy 5: step(s) 1013 do not belong to this policy
  • Version conflict (code 40): someone saved first. The answer carries the current version. Reload and decide again. The whole save is refused if any step is stale.

Picker (putaway_criterion_vocabulary):

  • an attribute_code was sent without a property — the property is chosen first, and which attributes exist depends on it
  • a 'LocationType' criterion narrows a column of its own, so it takes no attribute_code — this request still carries 'COLOR'. Clear it, or pick the attribute property you meant.
  • 'LotPolicy' is not a criterion property the putaway engine knows. It offers: LocationType, LocationStatus, ...

4.5 Settings that tune the engine (system level)​

SettingWhereDefaultEffect
PUTAWAY_RESERVATION_TTL_MINSidebar > System Settings (system_settings)15 (seed BASELINE:9955); code fallback 15 (reserve.rs:22)Minutes a suggested location is held. After that a sweeper (every 5 minutes) frees it.
Putaway Reservation TTL (min)Owner, WH Settings (owner_config.putaway_reservation_ttl_min)blank = use the warehouse valueOverrides the system setting for that owner. Must be above 0.
PUTAWAY_LOCK_TIMEOUT_MSsystem_settingsSeeded 5000 (wms-app 091). Code default 5000 ms (DEFAULT_LOCK_TIMEOUT_MS)How long one reservation waits for a busy location. A value of 0 or less is ignored (0 would mean "wait forever").
COUNT_ON_PUTAWAY_DEVIATIONsystem_settings (migration 071)01 = when an operator accepts a deviation (code 85) from the suggestion, the destination location is queued for a count.

Reservation order: owner TTL, then PUTAWAY_RESERVATION_TTL_MIN, then its default, then 15 (reserve.rs:346-351, ttl_minutes).


5. The "never runs" mark​

A step is marked never runs when an earlier step already takes everything it could take. The mark reads closed by step N (S). The rule is on purpose cautious. It says "never runs" only when the settings prove it (wms-lib-core/src/model/policies/putaway_step_shadow.rs:130-168). The earlier step must, on every point, be at least as wide:

PointCondition for "closed"
GuardEarlier has no guard, or the same guard and anchor.
Pallet conditionsEach earlier pallet condition is implied by a later one (same property and attribute; is subset, is not superset).
Search spaceSame scope, and the same zone/location for the two "named on this step" scopes.
TemperatureLater checks it whenever earlier does.
OrderingSame value.
Location conditionsEqual sets (not subsets), because of the 100-candidate scan limit.
ModeNot (Consolidate earlier and Suitable later).
MixingLater is at least as strict.
Fit checksLater checks everything earlier checks.

Steps with AssignedSlot, NearestToSlot or a missing anchor are never marked.

6. The dry run​

Panel Dry run (heading), field LPN / container, button Evaluate. Hint lines: evaluates the whole policy, not just this step and evaluates the SAVED policy — an edit is previewed only after Save. It runs the real engine on a real pallet and then rolls back (putaway/command.rs, explain_location). Nothing is reserved. Role: Admin, Manager, Supervisor.

Result columns: Candidate location, Rule, Outcome, Detail. Heading On this pallet lists the lines. Messages:

  • Type an LPN to see what the engine would do with it.
  • The engine would not evaluate this pallet: <reason>
  • Nothing is on LPN X — the engine has no pallet to place.
  • LPN X is loose stock rather than a container, and the putaway engine places containers — there is nothing here for it to put away.
  • What is on LPN X resolves to policy 7, not policy 5 — a dry run over it would not exercise these steps. Try an LPN whose SKUs point at this policy.
  • The engine reached no policy at all for LPN X, so there is nothing to compare policy 5's steps against.
  • Winner: step 02 (20) wins — the engine would put this pallet into B-04-2. (the label is step <position> (<stored number>), dry_run.rs:918-924).
  • No winner: No step offers a location: every candidate in every step was refused. or another request already holds this pallet's reservation, so the scan stopped early.
  • Per step: step 01 (10) is not about this pallet: its SkuAbc condition does not hold for what is on it., step 01 (10) was skipped: its guard limits it to stock that came from somewhere else., ... was skipped: it resolved no zone to search., ... was skipped: it resolved no location to search., ... was skipped: its zone's temperature range does not suit every line on this pallet., step 03 (30) was not reached — an earlier step matched first.
  • A reservation is not made. The error on a failed call: The dry run could not be made. Try again, or refresh the screen.