The plan came back complete and forty stops are not in it
In short
Unassigned stops mean one constraint family is binding, and arguing about which one wastes a morning. Re-solve the same instance with a single family relaxed each time — drop penalty, time windows, capacity, shift length, vehicle eligibility, depot hours — and the relaxation that admits the stops names the cause. 6 runs settle it.
Key takeaways
- Check the input count first. A stop that never reached the solver is a pipeline bug, and it looks identical to a dropped one on the dispatch screen.
- Most engines let a stop be skipped for a penalty, so infeasibility is reported as economics. Raise the penalty far above any routing cost and see which stops still refuse to fit.
- Relax exactly one constraint family per run, always from the same baseline. Two relaxations at once tells you nothing about either.
- Solve each unassigned stop alone with the full fleet. A stop no single vehicle can serve is impossible on its own terms, and no amount of extra capacity fixes it.
- A genuine capacity shortfall is provable in arithmetic before any solver runs: total demand against total fleet capacity, and total work against total shift minutes.
Forty unassigned stops means one constraint family is binding, and the fastest route to knowing which is not discussion. It is re-solving the same instance five or six times, relaxing exactly one family per run, and reading off which relaxation lets the stops in. The procedure takes an afternoon, produces an answer nobody can argue with, and ends at a lever the operation can pull rather than at a theory about the solver.
Before any of that, one check that catches a surprising share of these mornings: count the stops that went in against the stops that came back, assigned and unassigned combined. If the totals do not reconcile, nothing was dropped — something never arrived, and you are debugging an import rather than a model. Order feeds that silently discard records without a geocode are the usual culprit, and the failure looks identical on a dispatch board to a genuine constraint problem. Everything else in routing, dispatch and optimisation assumes the instance you solved is the instance you meant to solve.
Why the plan reports success while stops sit outside it
A strict vehicle routing model with hard constraints has only two outcomes: a plan that serves every stop, or no plan at all. Production systems find the second outcome unusable — a dispatch desk cannot be handed nothing at 06:00 — so almost every implementation makes visits optional at a price. In Google's OR-Tools the mechanism is AddDisjunction, which takes a node and a penalty and permits the solver to skip that node by paying it. The penalty is expressed in the same units as the arc costs the model already accumulates.
The consequence is that infeasibility stops being reported as infeasibility. It arrives as economics: the solver decided that serving those forty stops cost more than the penalty for abandoning them, and returned a solution it considers optimal. Whether a stop was impossible or merely expensive is a distinction the output does not draw for you, and it is the first thing the ladder resolves.
A solver that can skip a stop for a fee will never tell you the day was impossible. It will tell you what it decided to give up.
The ladder: one constraint family per run
Every run starts from the same frozen baseline instance and changes exactly one thing. Combining relaxations is the mistake that turns a clean diagnosis into a week of guessing, because two relaxations that each admit twenty stops may be admitting the same twenty.
- Baseline. Record the exact unassigned set, the objective value, and the drop penalty in force. Keep the list of stop identifiers — every later run is compared against it.
- Raise the drop penalty by a factor of 100 above the largest plausible routing cost in the instance. Stops that now get served were never infeasible; they were unprofitable, and the answer is a penalty scale that reflects what a missed delivery actually costs you.
- Widen every time window by 60 minutes at each end, leaving everything else alone. A large recovery here means windows and travel time are mutually exclusive as recorded — and the enforcement class matters as much as the times, which is the subject of hard and soft time windows in a route plan.
- Add one virtual vehicle with the same profile and capacity as your most common unit, starting at the busiest depot. Stops that appear only now are a fleet-size result, not a modelling one.
- Extend every shift by 60 minutes, keeping the fleet unchanged. This separates a capacity shortfall in volume from a shortfall in time, and the two have completely different remedies.
- Remove every vehicle-to-stop eligibility rule — skills, profiles, allowed-vehicle sets. A large recovery here means an eligibility rule is excluding more vehicles than whoever wrote it realised.
- Open the depot 60 minutes earlier and close it 60 minutes later. Depot hours clip the working day at both ends and are routinely modelled as an afterthought.
Reading a rung back into something the operation can change
| Relaxation that worked | What was actually binding | The lever, in order of preference |
|---|---|---|
| Higher drop penalty | Nothing. The model was trading these stops away deliberately | Reprice the penalty against the real cost of a missed delivery, then re-solve |
| Wider time windows | Promises and travel time cannot both be true as recorded | Audit the windows against recorded arrivals; reclassify preferences currently recorded as hard |
| One more vehicle | Volume or weight exceeds what the fleet can carry today | Move stops to another day, hire a unit, or split the largest orders |
| Longer shifts | Total driving plus service minutes exceeds total shift minutes | Attack service time first — it is usually the larger and the more wrong of the two |
| Eligibility rules removed | A skill or profile rule excludes almost every vehicle | Find the rule, check whether anyone has ever served the stop with a different unit, and narrow it |
| Longer depot hours | The working day is being clipped before the first stop and after the last | Stagger departures, or model the loading bay as the constraint it actually is |
The one stop that makes the whole day impossible
A single badly recorded stop can force dozens of others out, and the ladder can point at the wrong family when it does. The isolating test is direct: solve each unassigned stop on its own, with the entire fleet available and no other work in the instance. A stop that cannot be served even then is impossible on its own terms — the window closes before any vehicle can physically reach it, or its demand exceeds the largest vehicle you own, or no vehicle is eligible.
The causes are mundane and almost always data. A window typed as 09:00 to 09:00. A weight in kilograms in a field the model reads as tonnes. A coordinate that landed in the wrong country and made the leg a twelve-hour drive — a fault that also produces sequences that look absurd on a map, which is the diagnosis in the route crosses its own path twice. Run the single-stop test before the ladder if the unassigned set is small and scattered; run it after if the set is large and clustered.
When the fleet really is short, and how to say so credibly
The uncomfortable outcome of the ladder is that nothing was wrong: the constraints were accurate, the data was clean, and there was more work than fleet. That answer is worth as much as any of the others, provided it comes with the numbers. Present the demand-to-capacity ratio per dimension, the number of stops recovered by exactly one extra vehicle, and the marginal utilisation that extra vehicle would run at. A desk that receives an unexplained short plan blames the software; a desk that receives a ratio and a one-vehicle experiment argues about the fleet instead.
Watch the capacity dimensions carefully here. A load that is simultaneously heavy, bulky and carried in fixed-footprint cages is short in whichever dimension binds first, and models that track only weight will report plenty of room while the vehicle is physically full — the failure taken apart in modelling weight, volume, pallets and cages together.
Three things the ladder will not tell you
- Whether the travel times were right in the first place. Every rung assumes the matrix is honest. A matrix built at free-flow speeds, or built once at 09:00 and reused all day, makes afternoon legs look cheaper than they are and pushes the infeasibility somewhere else entirely — the caching decisions that keep it honest are in building a travel-time matrix you can afford to rebuild every morning.
- Whether the vehicles exist. If the fleet list includes a unit that is off the road, or starts a route from a depot the vehicle left last night, the ladder will happily report that capacity was sufficient. Stale fleet state has its own diagnosis in the map is open and the vehicles have stopped moving.
- Whether the solve simply ran out of time. A search cut short can leave stops unassigned that a longer run would have placed, which looks exactly like a constraint problem and is not — separated properly in the solve still has not finished and the first van is loaded.
Run the ladder as a script rather than by hand, and keep the results. The same seven runs against a normal Tuesday and against a peak Friday tell you which constraint binds first as volume rises, which is the most useful piece of planning intelligence a routing system can produce and one almost nobody extracts from it. Wiring that into a repeatable job is straightforward product and platform work, and it turns a recurring argument into a standing report for any logistics and mobility operation running daily plans.
Frequently asked questions
Short answers to the follow-ups this page tends to raise.
Why does route optimisation software return a plan with stops unassigned instead of an error?
Because most production configurations make visits optional at a penalty, so the solver always has a valid answer available. In OR-Tools that is done with AddDisjunction, which lets a node be skipped in exchange for a cost. The result is that an infeasible day is reported as an economic decision rather than as a failure, and you cannot tell from the output whether a stop was impossible or merely expensive.
How do I find which constraint is causing unassigned stops?
Re-solve the same instance once per constraint family, relaxing exactly one family each time and always starting from the same baseline. Raise the drop penalty, widen time windows, add a vehicle, extend shifts, remove eligibility rules, and open depot hours — in separate runs. The relaxation that admits the stops identifies the binding family, usually within six runs.
One stop is unassigned and nothing else. What is wrong with it?
Solve that stop on its own with the whole fleet available. If it still cannot be served, the stop itself is impossible as recorded, and the causes are almost always data: a zero-width time window, a demand larger than any vehicle, a unit-of-measure error, or a coordinate in the wrong place. If it is served fine alone, it is competing with other work and belongs back in the ladder.
Does adding vehicles always fix unassigned stops?
No, and reaching for it first hides the real cause. Extra vehicles only help when volume or weight is binding; they do nothing when a time window is mutually exclusive with travel time, when an eligibility rule excludes every unit, or when a single stop is impossible on its own terms. The one-extra-vehicle run exists to test that hypothesis, not to implement it.
- route optimisation
- infeasibility
- constraints
- dispatch
The work behind this page
Builds from our portfolio that this page draws on.
Read next
- The solve still has not finished and the first van is loadedMost teams tune the solver and wait longer. In production systems the matrix is usually the slow half, and no search parameter touches it.diagnostic
- The route crosses itself twice and the driver has already resequenced itA route that doubles back is either obeying a constraint the map cannot draw or genuinely bad. Only one of those is fixed by re-optimising; the other is fixed by explaining.diagnostic
- Service time: the minutes at the kerb that decide the planEvery route plan carries an assumption about how long a stop takes. In most fleets it is one number, applied everywhere, and nobody has ever measured it.definition
- The optimiser made a plan and the desk rebuilt it by hand before eightSystematic override is not resistance to change. It is an unwritten requirements document being typed into your software every morning, one drag-and-drop at a time.diagnostic
- The travel-time matrix: the input that decides the planThe solver never sees a road. It sees a table of durations between every pair of stops, and every mistake in that table becomes a plan that cannot be driven.definition
- Vehicle profile: why a car route and a truck route are different networksA consumer navigation route given to a heavy vehicle is not a rough version of the right answer. It is a route through roads the vehicle is not allowed to use.definition
Working on something in this space?
Tell us where you are in a sentence or two. We'll tell you honestly whether we're the right team, and what a sensible first slice of the work looks like.
Start the conversation