Map route violations to control job assignment
Route violations such as traffic closures, avoid areas, or physical restrictions can cause the optimization algorithm to leave a job unassigned in a tour. However, fleet operators often need fine-grained control over which violations to accept and how to track them. For example, a delivery fleet operator might want to allow trucks to cross a closed bridge to meet urgent delivery deadlines, but still refuse to assign jobs blocked by a height restriction due to safety concerns, and needs to know which stops carry a routing risk.
violationMapping solves this by classifying violations into named categories so that jobs affected by different violation types are distinguishable in the solution. An accompanying property, ignoreRouteViolations, then tells the optimization algorithm which categories to treat as reachable. Together, the two properties give you control over assignment and risk tracking per each violation type that you mapped.
You can map the following violation types:
traffic: Violations caused by temporary or permanent road closures, for example, due to construction, accidents, or other traffic-related events. Supported for vehicle profiles of typecarandtruck.avoidAreasAndSegments: Areas or road segments explicitly marked to be avoided, for example, private roads, or features such as tunnels. Supported for vehicle profiles of typecarandtruck.restriction: Physical or legal constraints such as height, weight, or width limits that prevent vehicle access to a job location. Supported for thetruckvehicle profile only.
Note
This is an ALPHA feature in active development. Enable it by adding
"violationMapping"to theexperimentalFeaturesarray in your problem'sconfigurationobject.For more information, see Explore experimental features.
How violation mapping works
The violationMapping feature operates in the two-step mechanism:
- Step 1:
violationMappingclassifies a violation into a named category:category1orcategory2. - Step 2:
ignoreRouteViolationstells the optimization algorithm whether to treat stops in that category as reachable.
The following snippet shows the minimal structure of violationMapping inside a vehicle profile. It maps a single violation type to a single category and tells the algorithm to ignore violations in that category:
"profiles": [
{
"name": "my_truck",
"type": "truck",
"violationMapping": [
{
"category": "category1",
"type": "traffic"
}
],
"ignoreRouteViolations": ["category1"]
}
]As the previous example shows, both violationMapping and ignoreRouteViolations are set inside the fleet.profiles array. This example provides the baseline pattern for violation mapping. Each more advanced configuration that this article demonstrates follows the same pattern with some additional elements layered on top. In this specific example:
categoryis the bucket labeltypeis the violation class that is being mappedignoreRouteViolationsis the list that activates the ignore behavior for thecategorybucket
The following flow shows how the two steps work together and what determines whether a stop is assigned or left unassigned, based on the previous example:
flowchart LR
A([<b>Route violation<br/>occurs</b>]) ==> B["<b>Step 1</b><br/>violationMapping<br/>classifies it into<br/><b>category1</b>"]
B ==> C{"<b>Step 2</b><br/>Is category1 listed<br/>in ignoreRouteViolations?"}
C -- Yes --> D([Stop <b>assigned</b><br/>with unreachableLocation<br/>notice])
C -- No --> E([Stop <b>unassigned</b><br/>with REACHABLE_CONSTRAINT <br/>notice])
style A fill:#0060B0,stroke:#002831,color:#FFFFFF
style B fill:#36C1C4,stroke:#007A76,color:#FFFFFF
style C fill:#1A1A2E,stroke:#0F0F1A,color:#FFFFFF
style D fill:#0060B0,stroke:#002831,color:#FFFFFF
style E fill:#6B7280,stroke:#4B5563,color:#FFFFFF
The available category names (category1, category2) are arbitrary bucket names and their meaning is defined by the violation you map into them. For example, you can map traffic closures into category1 as acceptable violations because the driver can walk the last stretch of the route on foot. In the same way, you can map height restrictions into category2 as the violations that are unacceptable, keeping those stops unassigned while still tracking which stops carry that risk.
In addition to category1 and category2, the following range of ignoreRouteViolations values caters to multiple use cases when used together with violationMapping:
| Value | Behavior |
|---|---|
category1 | Ignores violations mapped to category1. Stops in category1 are assigned with an unreachableLocation notice. |
category2 | Ignores violations mapped to category2. Stops in category2 are assigned with an unreachableLocation notice. |
allExceptCategory1 | Ignores all violations except those mapped to category1. Stops blocked by category1 violations remain unassigned. |
allExceptCategory2 | Ignores all violations except those mapped to category2. Stops blocked by category2 violations remain unassigned. |
allExceptCategory1AndCategory2 | Ignores all violations except those mapped to category1 or category2. Stops blocked by either category remain unassigned. |
The allExcept* values are useful when you want to assign most stops regardless of routing violations, but explicitly keep a specific category unassigned. For example, to preserve a hard safety rule for height-restricted stops while accepting all other violation types.
Note
Keep the following constraints in mind:
- The
violationMappingarray can contain no more than 10 unique combinations ofcategoryandtype.- Each item in the array must reference exactly one
typeand onecategory.- The same category can appear in multiple items, but the same
typecannot repeat within the same category, unless the type references different sub-fields.- You cannot combine
violationMappingwithignoreRouteViolations: ["all"]or the deprecatedignoreRouteViolations: ["traffic"], as doing so returns an error.For more information, see API Reference.
Control which violations are captured
Some violation types use sub-fields that allow for more fine-grained selection of violations a mapping item captures, based on the specific properties of the restriction. The available sub-fields depend on the violation type:
restriction:height,grossWeight,currentWeight,bridge,timeDependenttraffic:bridgeavoidAreasAndSegments: no sub-fields
Each sub-field accepts one of three values: "include" (the property must apply), "exclude" (the property must not apply), or "ignore" (the property is not checked).
For example, consider a tall truck approaching a stop that can only be reached through a height-restricted road. The following table shows what each value does and what its default is:
| Value | What it means | Result for the truck example | Default for |
|---|---|---|---|
"include" | Map the violation only when this property applies to the restriction | Height restriction applies → violation mapped | — |
"exclude" | Block mapping when this property applies to the restriction | Height restriction applies → violation not mapped → job unassigned (REACHABLE_CONSTRAINT) | height, grossWeight, currentWeight |
"ignore" | This property is not checked; the mapping applies regardless | Height restriction applies, but height is not checked → violation mapped | bridge, timeDependent |
For more information on the violation mapping mechanism, see Violation mapping in HERE Matrix Routing API v8.
Sample use cases involving violation mapping
The following examples cover each violation type in order of complexity, starting with simple configurations and building toward more advanced ones.
Map traffic violations
This example applies the baseline violationMapping pattern directly. In that pattern, all traffic violations are mapped to category1, which the optimization algorithm is told to ignore. In the example scenario, a delivery truck needs to deliver to three stops in an area where some roads are affected by live traffic closures. The fleet operator wants to ensure that all stops are assigned regardless of closures, and needs to know which stops carry traffic-related routing risks.
The following figure shows the depot and job locations as well as the road closure that could trigger route violations:
Warning
Traffic conditions change continuously. Solutions produced by traffic-based violation mapping examples may differ from recorded outputs because live road closure data varies by time and location. Use the provided problem JSON as the reference input and treat any solution JSON in this article as illustrative rather than reproducible.
In that file, the delivery_truck profile is configured to ignore all traffic-related violations as part of category1, as the following snippet demonstrates:
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"ignoreRouteViolations": ["category1"],
"violationMapping": [
{
"category": "category1",
"type": "traffic"
}
]
}
]The expected outcome for that configuration is that all traffic-related violations are ignored by the optimization algorithm which results in all jobs being assigned to a tour. The following section contains the full problem file:
Click to expand/collapse the sample JSON
{
"configuration": { "experimentalFeatures": ["violationMapping"] },
"fleet": {
"types": [
{
"profile": "delivery_truck",
"amount": 1,
"capacity": [30],
"costs": { "fixed": 10, "time": 0.002, "distance": 0.001 },
"id": "vehicle_1",
"shifts": [
{
"start": {
"time": "2026-05-15T08:30:00Z",
"location": { "lat": 52.418586957426044, "lng": 13.205656324722792 }
}
}
]
}
],
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"ignoreRouteViolations": ["category1"],
"violationMapping": [
{
"category": "category1",
"type": "traffic"
}
]
}
]
},
"plan": {
"jobs": [
{
"id": "Job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.42190948288694, "lng": 13.19405542552992}
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_2",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.421612477457856, "lng": 13.20251576168617 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_3",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.422268864749725, "lng": 13.189670501127011 }
}
],
"demand": [1]
}
]
}
}
]
}
}Solution interpretation - Traffic example
In the resulting solution, the optimization algorithm assigned all jobs, as expected and all the jobs that carry a routing risk (Job_1 and Job_3) come with an associated warning message that highlights the violation type (category1), for example:
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]For more information, see the full solution JSON:
Click to expand/collapse the sample JSON
{
"statistic": {
"cost": 29.093,
"distance": 14971,
"duration": 2061,
"times": {
"driving": 1161,
"serving": 900,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"tours": [
{
"vehicleId": "vehicle_1_1",
"typeId": "vehicle_1",
"stops": [
{
"time": {
"arrival": "2026-05-15T08:30:00Z",
"departure": "2026-05-15T08:30:00Z"
},
"load": [
3
],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.41858695742605,
"lng": 13.205656324722792
},
"time": {
"start": "2026-05-15T08:30:00Z",
"end": "2026-05-15T08:30:00Z",
"arrival": "2026-05-15T08:30:00Z"
}
}
],
"location": {
"lat": 52.41858695742605,
"lng": 13.205656324722792
},
"distance": 0
},
{
"time": {
"arrival": "2026-05-15T08:32:35Z",
"departure": "2026-05-15T08:37:35Z"
},
"load": [
2
],
"activities": [
{
"jobId": "Job_2",
"type": "delivery",
"location": {
"lat": 52.421612477457856,
"lng": 13.20251576168617
},
"time": {
"start": "2026-05-15T08:32:35Z",
"end": "2026-05-15T08:37:35Z",
"arrival": "2026-05-15T08:32:35Z"
}
}
],
"location": {
"lat": 52.421612477457856,
"lng": 13.20251576168617
},
"distance": 582
},
{
"time": {
"arrival": "2026-05-15T08:52:34Z",
"departure": "2026-05-15T08:57:34Z"
},
"load": [
1
],
"activities": [
{
"jobId": "Job_1",
"type": "delivery",
"location": {
"lat": 52.42190948288694,
"lng": 13.19405542552992
},
"time": {
"start": "2026-05-15T08:52:34Z",
"end": "2026-05-15T08:57:34Z",
"arrival": "2026-05-15T08:52:34Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.42190948288694,
"lng": 13.19405542552992
},
"distance": 14113
},
{
"time": {
"arrival": "2026-05-15T08:59:21Z",
"departure": "2026-05-15T09:04:21Z"
},
"load": [
0
],
"activities": [
{
"jobId": "Job_3",
"type": "delivery",
"location": {
"lat": 52.422268864749725,
"lng": 13.189670501127011
},
"time": {
"start": "2026-05-15T08:59:21Z",
"end": "2026-05-15T09:04:21Z",
"arrival": "2026-05-15T08:59:21Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.422268864749725,
"lng": 13.189670501127011
},
"distance": 14971
}
],
"statistic": {
"cost": 29.093,
"distance": 14971,
"duration": 2061,
"times": {
"driving": 1161,
"serving": 900,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"shiftIndex": 0
}
]
}Map avoid area violations
This example applies the same pattern to a different violation type: avoidAreasAndSegments. In this scenario, the fleet defines a bounding box avoid area that represents a restricted delivery zone or a congested district (the avoid.areas object in the profile can contain a bounding box, polygon, encoded polygon, or a feature). Some job locations fall inside this zone, so the algorithm cannot route the vehicle to them without crossing the avoided area. For the visual representation of the job location as well as the bounding box to avoid, see the following figure:
The following snippet shows the delivery_truck profile configuration with avoid.areas as well as the corresponding violationMapping configuration:
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"avoid": {
"areas": [
{
"type": "boundingBox",
"north": 52.508064,
"south": 52.50677,
"east": 13.394407,
"west": 13.392137
}
]
},
"ignoreRouteViolations": ["category1"],
"violationMapping": [
{
"category": "category1",
"type": "avoidAreasAndSegments"
}
]
}
]The following section shows the full problem JSON. The expected behavior is that the optimization algorithm ignores the bounding box violations and assigns all jobs to the tour.
Click to expand/collapse the sample JSON
{
"configuration": { "experimentalFeatures": ["violationMapping"] },
"fleet": {
"types": [
{
"profile": "delivery_truck",
"amount": 1,
"capacity": [30],
"costs": { "fixed": 10, "time": 0.002, "distance": 0.001 },
"id": "vehicle_1",
"shifts": [
{
"start": {
"time": "2026-05-15T08:30:00Z",
"location": { "lat": 52.5062838773854, "lng": 13.386458504898345 }
}
}
]
}
],
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"avoid": {
"areas": [
{
"type": "boundingBox",
"north": 52.508064,
"south": 52.50677,
"east": 13.394407,
"west": 13.392137
}
]
},
"ignoreRouteViolations": ["category1"],
"violationMapping": [
{
"category": "category1",
"type": "avoidAreasAndSegments"
}
]
}
]
},
"plan": {
"jobs": [
{
"id": "Job_1",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.505941151875504, "lng": 13.392387263950676}
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_2_bbox",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.50773539109499, "lng": 13.3935796400729 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_3_bbox",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.50706003998471, "lng": 13.393215302924446 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_4",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.5084913688343, "lng": 13.391492981859013}
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_5_bbox",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.5075337948351, "lng": 13.39256943252489 }
}
],
"demand": [1]
}
]
}
}
]
}
}Solution interpretation - Avoid area example
The optimization algorithm assigns all jobs to the tour, as shown in the following solution. All jobs that carry a routing risk contain the corresponding notice about violating a restriction.
The following figure shows that the optimization algorithm routed the vehicle to the job locations, despite those jobs being located inside an avoid bounding box:
See the following section for the full solution JSON:
Click to expand/collapse the solution JSON
{
"statistic": {
"cost": 16.364,
"distance": 2256,
"duration": 2054,
"times": {
"driving": 554,
"serving": 1500,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"tours": [
{
"vehicleId": "vehicle_1_1",
"typeId": "vehicle_1",
"stops": [
{
"time": {
"arrival": "2026-05-15T08:30:00Z",
"departure": "2026-05-15T08:30:00Z"
},
"load": [
5
],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"time": {
"start": "2026-05-15T08:30:00Z",
"end": "2026-05-15T08:30:00Z",
"arrival": "2026-05-15T08:30:00Z"
}
}
],
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"distance": 0
},
{
"time": {
"arrival": "2026-05-15T08:31:54Z",
"departure": "2026-05-15T08:36:54Z"
},
"load": [
4
],
"activities": [
{
"jobId": "Job_5_bbox",
"type": "delivery",
"location": {
"lat": 52.5075337948351,
"lng": 13.39256943252489
},
"time": {
"start": "2026-05-15T08:31:54Z",
"end": "2026-05-15T08:36:54Z",
"arrival": "2026-05-15T08:31:54Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.5075337948351,
"lng": 13.39256943252489
},
"distance": 534
},
{
"time": {
"arrival": "2026-05-15T08:37:17Z",
"departure": "2026-05-15T08:42:17Z"
},
"load": [
3
],
"activities": [
{
"jobId": "Job_2_bbox",
"type": "delivery",
"location": {
"lat": 52.50773539109499,
"lng": 13.3935796400729
},
"time": {
"start": "2026-05-15T08:37:17Z",
"end": "2026-05-15T08:42:17Z",
"arrival": "2026-05-15T08:37:17Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.50773539109499,
"lng": 13.3935796400729
},
"distance": 656
},
{
"time": {
"arrival": "2026-05-15T08:43:09Z",
"departure": "2026-05-15T08:48:09Z"
},
"load": [
2
],
"activities": [
{
"jobId": "Job_3_bbox",
"type": "delivery",
"location": {
"lat": 52.50706003998471,
"lng": 13.393215302924446
},
"time": {
"start": "2026-05-15T08:43:09Z",
"end": "2026-05-15T08:48:09Z",
"arrival": "2026-05-15T08:43:09Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.50706003998471,
"lng": 13.393215302924446
},
"distance": 884
},
{
"time": {
"arrival": "2026-05-15T08:49:49Z",
"departure": "2026-05-15T08:54:49Z"
},
"load": [
1
],
"activities": [
{
"jobId": "Job_4",
"type": "delivery",
"location": {
"lat": 52.5084913688343,
"lng": 13.391492981859011
},
"time": {
"start": "2026-05-15T08:49:49Z",
"end": "2026-05-15T08:54:49Z",
"arrival": "2026-05-15T08:49:49Z"
}
}
],
"location": {
"lat": 52.5084913688343,
"lng": 13.391492981859011
},
"distance": 1367
},
{
"time": {
"arrival": "2026-05-15T08:59:14Z",
"departure": "2026-05-15T09:04:14Z"
},
"load": [
0
],
"activities": [
{
"jobId": "Job_1",
"type": "delivery",
"location": {
"lat": 52.505941151875504,
"lng": 13.392387263950676
},
"time": {
"start": "2026-05-15T08:59:14Z",
"end": "2026-05-15T09:04:14Z",
"arrival": "2026-05-15T08:59:14Z"
}
}
],
"location": {
"lat": 52.505941151875504,
"lng": 13.392387263950676
},
"distance": 2256
}
],
"statistic": {
"cost": 16.364,
"distance": 2256,
"duration": 2054,
"times": {
"driving": 554,
"serving": 1500,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"shiftIndex": 0
}
]
}Map vehicle restriction violations
This example uses the restriction violation type to show how sub-field affect which violations are captured, and how two restriction types can be mapped to separate categories.
Mapping multiple restriction types:
includevsignoreSetting multiple sub-fields to
includein one item requires all of them to be present on the restriction at the same time. For example, considergrossWeightandcurrentWeight. In practice, no restriction carries both agrossWeightand acurrentWeightcondition simultaneously, so setting both toincludein a single item means the mapping never happens.Use
ignoreinstead to map a violation when any of the specified properties apply, as shown in the following table:
Goal Configuration Map only grossWeightviolations"grossWeight": "include"Map only currentWeightviolations"currentWeight": "include"Map either grossWeightorcurrentWeightviolations"grossWeight": "ignore", "currentWeight": "ignore"Map either, but only on a bridge "grossWeight": "ignore", "currentWeight": "ignore", "bridge": "include"
In this sample scenario, a fleet of tall, heavy delivery trucks (height: 800 cm, grossWeight: 8000 kg) must deliver to stops in an area with both height-restricted and weight-restricted roads. The fleet operator wants all stops assigned regardless of restrictions, but needs the solution to identify which stops were affected by which type of violation.
Therefore, the profile maps each restriction type to a separate category:
category1captures height violations (height: "include")category2captures gross weight violations (grossWeight: "include")
Note
- Putting
height: "include"andgrossWeight: "include"in the same mapping item (for example,category2) would create a condition in which for the mapping to occur, the stop must be blocked by both theheightANDgrossWeightrestriction. In the context of this sample scenario, such configuration would result in no jobs being assigned.- As an alternative to the configuration presented in the example, you can set both
heightandgrossWeightto"ignore"and then place them under a single mapping category. However, the resulting notices in the solution do not differentiate between violation types as both fall under the same category.- A single stop activity can record multiple violated categories. If the vehicle encounters different restrictions while approaching a stop (for example, a weight restriction on one segment and a height restriction on another), the activity’s notices may list multiple categories to reflect each recorded violation.
Both categories are listed in ignoreRouteViolations, so the expected outcome is that all stops are assigned.
The following figure shows the job distribution in this example and visualizes the restriction that could block routing to those locations:
The restriction type is supported for the truck profile only. Attempting it with any other profile type returns an API validation error. In addition, you must set at least one of height, grossWeight, or currentWeight to include or ignore in each restriction item as omitting all three returns an error.
The following snippet shows the delivery_truck profile configuration:
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"options": {
"height": 800,
"grossWeight": 8000
},
"ignoreRouteViolations": ["category1", "category2"],
"violationMapping": [
{
"category": "category1",
"type": "restriction",
"height": "include"
},
{
"category": "category2",
"type": "restriction",
"grossWeight": "include"
}
]
}
]Key points about this configuration:
options.height: 800andoptions.grossWeight: 8000define the vehicle's physical dimensions. The routing engine compares these against road segment restrictions to determine whether a violation occurs.- The two
violationMappingitems use separate categories, one per restriction type. - Because
heightandgrossWeightboth default toexclude, they must be explicitly set toinclude. Without this, both restriction types would cause errors.
See the following section for the full problem JSON:
Click to expand/collapse the sample JSON
{
"configuration": { "experimentalFeatures": ["violationMapping"] },
"fleet": {
"types": [
{
"profile": "delivery_truck",
"amount": 2,
"capacity": [1],
"costs": { "fixed": 10, "time": 0.002, "distance": 0.001 },
"id": "vehicle_1",
"shifts": [
{
"start": {
"time": "2026-05-15T08:30:00Z",
"location": { "lat": 52.5062838773854, "lng": 13.386458504898345 }
}
}
]
}
],
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"options": {
"height": 800,
"grossWeight": 8000
},
"ignoreRouteViolations": ["category1", "category2"],
"violationMapping": [
{
"category": "category1",
"type": "restriction",
"height": "include"
},
{
"category": "category2",
"type": "restriction",
"grossWeight": "include"
}
]
}
]
},
"plan": {
"jobs": [
{
"id": "Job_1_height",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.515983, "lng": 13.398930}
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_2_grossWeight",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.50292999778208, "lng": 13.396585347667896}
}
],
"demand": [1]
}
]
}
}
]
}
}Solution interpretation - Restriction example
All jobs are assigned. Each job that triggered a restriction violation carries an unreachableLocation notice identifying which category the violation was mapped to:
Job_1_heighttriggered a height restriction. Its notice referencescategory1.Job_2_grossWeighttriggered a gross weight restriction. Its notice referencescategory2.
The following figure shows the solution visualization:
The category label in the notice is what makes the solution actionable. A category1 notice tells the dispatcher the stop has a height risk; a category2 notice signals a weight risk. Without separate categories, both violation types would produce identical notices and the distinction would be lost.
Removing either category from ignoreRouteViolations would leave the corresponding stops unassigned. For example, removing category2 would keep Job_2_grossWeight unassigned while still assigning Job_1_height.
For the full solution JSON, see the following section:
Click to expand/collapse the sample JSON
{
"statistic": {
"cost": 29.302999999999997,
"distance": 5883,
"duration": 1710,
"times": {
"driving": 1110,
"serving": 600,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"tours": [
{
"vehicleId": "vehicle_1_1",
"typeId": "vehicle_1",
"stops": [
{
"time": {
"arrival": "2026-05-15T08:30:00Z",
"departure": "2026-05-15T08:30:00Z"
},
"load": [
1
],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"time": {
"start": "2026-05-15T08:30:00Z",
"end": "2026-05-15T08:30:00Z",
"arrival": "2026-05-15T08:30:00Z"
}
}
],
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"distance": 0
},
{
"time": {
"arrival": "2026-05-15T08:36:14Z",
"departure": "2026-05-15T08:41:14Z"
},
"load": [
0
],
"activities": [
{
"jobId": "Job_2_grossWeight",
"type": "delivery",
"location": {
"lat": 52.50292999778208,
"lng": 13.396585347667896
},
"time": {
"start": "2026-05-15T08:36:14Z",
"end": "2026-05-15T08:41:14Z",
"arrival": "2026-05-15T08:36:14Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category2), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.50292999778208,
"lng": 13.396585347667896
},
"distance": 1936
}
],
"statistic": {
"cost": 13.284,
"distance": 1936,
"duration": 674,
"times": {
"driving": 374,
"serving": 300,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"shiftIndex": 0
},
{
"vehicleId": "vehicle_1_2",
"typeId": "vehicle_1",
"stops": [
{
"time": {
"arrival": "2026-05-15T08:30:00Z",
"departure": "2026-05-15T08:30:00Z"
},
"load": [
1
],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"time": {
"start": "2026-05-15T08:30:00Z",
"end": "2026-05-15T08:30:00Z",
"arrival": "2026-05-15T08:30:00Z"
}
}
],
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"distance": 0
},
{
"time": {
"arrival": "2026-05-15T08:42:16Z",
"departure": "2026-05-15T08:47:16Z"
},
"load": [
0
],
"activities": [
{
"jobId": "Job_1_height",
"type": "delivery",
"location": {
"lat": 52.515983,
"lng": 13.39893
},
"time": {
"start": "2026-05-15T08:42:16Z",
"end": "2026-05-15T08:47:16Z",
"arrival": "2026-05-15T08:42:16Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.515983,
"lng": 13.39893
},
"distance": 3947
}
],
"statistic": {
"cost": 16.019,
"distance": 3947,
"duration": 1036,
"times": {
"driving": 736,
"serving": 300,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"shiftIndex": 0
}
]
}Use multiple categories and combine violation types
A single category can hold multiple violation mapping items of different types, which in situations when the operational response to all those violation types is identical and grouping them means that a single ignoreRouteViolations value covers all of them.
In this scenario a fleet of tall, heavy trucks (height: 800 cm, grossWeight: 8000 kg), serves five jobs across a mixed urban area. The associated vehicle profile contains the following violation mapping configuration:
- Three types of violations are operationally acceptable (traffic closures, avoid area crossings, and gross weight restrictions) and are grouped into
category1 - Height restrictions are the hard safety gate and go into
category2 ignoreRouteViolations: ["allExceptCategory2"]is the single value that covers the entire policy
The following snippet captures requirements for mapping violations:
"violationMapping": [
{ "category": "category1", "type": "traffic" },
{ "category": "category1", "type": "avoidAreasAndSegments" },
{ "category": "category1", "type": "restriction", "grossWeight": "include" },
{ "category": "category2", "type": "restriction", "height": "include" }
],
"ignoreRouteViolations": ["allExceptCategory2"]This configuration produces the following practical implications:
- Three violation types share
category1 - The
allExceptCategory2option covers all of the violation types to ignore with a single value because it ignores everything not mapped tocategory2 - Height is the only type in
category2 allExceptCategory2does not ignorecategory2, so height-blocked stops remain unassigned
The tour plan consists of the following jobs:
Job_1_heightandJob_4_height: require passing a height-restricted underpassJob_2_grossWeigth: requires passing a weight-restricted roadJob_3_traffic: blocked by a live traffic closureJob_5_bbox: falls inside an avoid bounding box
The following section contains the full problem configuration:
Click to expand/collapse the sample JSON
{
"configuration": { "experimentalFeatures": ["violationMapping"] },
"fleet": {
"types": [
{
"profile": "delivery_truck",
"amount": 1,
"capacity": [30],
"costs": { "fixed": 10, "time": 0.002, "distance": 0.001 },
"id": "vehicle_1",
"shifts": [
{
"start": {
"time": "2026-05-15T08:30:00Z",
"location": { "lat": 52.5062838773854, "lng": 13.386458504898345 }
}
}
]
}
],
"profiles": [
{
"name": "delivery_truck",
"type": "truck",
"options": {
"height": 800,
"grossWeight": 8000
},
"avoid": {
"areas": [
{
"type": "boundingBox",
"north": 52.463258,
"south": 52.461414,
"east": 13.313586,
"west": 13.309732
}
]
},
"violationMapping": [
{ "category": "category1", "type": "traffic" },
{ "category": "category1", "type": "avoidAreasAndSegments" },
{ "category": "category1", "type": "restriction", "grossWeight": "include" },
{ "category": "category2", "type": "restriction", "height": "include" }
],
"ignoreRouteViolations": ["allExceptCategory2"]
}
]
},
"plan": {
"jobs": [
{
"id": "Job_1_height",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.443484936711805, "lng": 13.348484551197322 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_2_grossWeigth",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.5028909960123, "lng": 13.397018480136607 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_3_traffic",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.49173924851315, "lng": 13.401725806085613 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_4_height",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.41796351389373, "lng": 13.314499243723935 }
}
],
"demand": [1]
}
]
}
},
{
"id": "Job_5_bbox",
"tasks": {
"deliveries": [
{
"places": [
{
"duration": 300,
"location": { "lat": 52.462269714892976, "lng": 13.311738706185261 }
}
],
"demand": [1]
}
]
}
}
]
}
}Solution interpretation - Multiple categories example
Based on the violationMapping and ignoreRouteViolations configuration in the previous problem, the optimization algorithm created the following tour:
Job_2_grossWeigth: assigned, notice referencescategory1(gross weight, explicitly mapped)Job_3_traffic: assigned, notice referencescategory1(traffic closure, explicitly mapped)Job_5_bbox: assigned, notice referencescategory1(avoid area, explicitly mapped)Job_1_heightandJob_4_height: unassigned withREACHABLE_CONSTRAINT(height mapped tocategory2, whichallExceptCategory2does not ignore)
The following figures show the job and restriction layout before optimization and the resulting tour plan:
| Problem | Solution |
|---|---|
![]() | ![]() |
Note
allExceptCategory2also ignores violations that were not captured by any mapping item. Those appear asallin the notice rather thancategory1. Thecategory1label is therefore a positive confirmation of intentional, tracked mapping. Theallvalue means the stop was assigned by the broad fallback, outside the explicit mapping configuration.
Expand the following section to see the full solution:
Click to expand/collapse the sample JSON
{
"statistic": {
"cost": 32.901,
"distance": 16227,
"duration": 3337,
"times": {
"driving": 2437,
"serving": 900,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"tours": [
{
"vehicleId": "vehicle_1_1",
"typeId": "vehicle_1",
"stops": [
{
"time": {
"arrival": "2026-05-15T08:30:00Z",
"departure": "2026-05-15T08:30:00Z"
},
"load": [
3
],
"activities": [
{
"jobId": "departure",
"type": "departure",
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"time": {
"start": "2026-05-15T08:30:00Z",
"end": "2026-05-15T08:30:00Z",
"arrival": "2026-05-15T08:30:00Z"
}
}
],
"location": {
"lat": 52.5062838773854,
"lng": 13.386458504898345
},
"distance": 0
},
{
"time": {
"arrival": "2026-05-15T08:35:43Z",
"departure": "2026-05-15T08:40:43Z"
},
"load": [
2
],
"activities": [
{
"jobId": "Job_2_grossWeigth",
"type": "delivery",
"location": {
"lat": 52.5028909960123,
"lng": 13.397018480136609
},
"time": {
"start": "2026-05-15T08:35:43Z",
"end": "2026-05-15T08:40:43Z",
"arrival": "2026-05-15T08:35:43Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.5028909960123,
"lng": 13.397018480136609
},
"distance": 1705
},
{
"time": {
"arrival": "2026-05-15T08:55:28Z",
"departure": "2026-05-15T09:00:28Z"
},
"load": [
1
],
"activities": [
{
"jobId": "Job_3_traffic",
"type": "delivery",
"location": {
"lat": 52.49173924851315,
"lng": 13.401725806085611
},
"time": {
"start": "2026-05-15T08:55:28Z",
"end": "2026-05-15T09:00:28Z",
"arrival": "2026-05-15T08:55:28Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.49173924851315,
"lng": 13.401725806085611
},
"distance": 5918
},
{
"time": {
"arrival": "2026-05-15T09:20:37Z",
"departure": "2026-05-15T09:25:37Z"
},
"load": [
0
],
"activities": [
{
"jobId": "Job_5_bbox",
"type": "delivery",
"location": {
"lat": 52.462269714892976,
"lng": 13.31173870618526
},
"time": {
"start": "2026-05-15T09:20:37Z",
"end": "2026-05-15T09:25:37Z",
"arrival": "2026-05-15T09:20:37Z"
},
"notices": [
{
"code": "unreachableLocation",
"title": "Due to ignored route violations (category1), this location can be unreachable",
"action": "Remove ignoreRouteViolations to be sure that location is reachable"
}
]
}
],
"location": {
"lat": 52.462269714892976,
"lng": 13.31173870618526
},
"distance": 16227
}
],
"statistic": {
"cost": 32.901,
"distance": 16227,
"duration": 3337,
"times": {
"driving": 2437,
"serving": 900,
"waiting": 0,
"stopping": 0,
"break": 0,
"intraStop": 0
},
"intraStopDistance": 0
},
"shiftIndex": 0
}
],
"unassigned": [
{
"jobId": "Job_1_height",
"reasons": [
{
"code": "REACHABLE_CONSTRAINT",
"description": "location unreachable"
}
]
},
{
"jobId": "Job_4_height",
"reasons": [
{
"code": "REACHABLE_CONSTRAINT",
"description": "location unreachable"
}
]
}
]
}Next steps
- To understand the foundational
ignoreRouteViolationsbehavior without categories, see Assign otherwise unreachable jobs by ignoring route violations. - To understand how traffic modes affect route calculation and when closures are active, see Understand traffic modes.
- To configure avoid areas and segments in the vehicle profile, see Use preferred routes with avoid options.
- To diagnose jobs that remain unassigned despite violation mapping configuration, see Troubleshoot unassigned jobs.
- For a full reference of
violationMapping,ignoreRouteViolations, and all supported sub-fields, see the API Reference.
Updated 9 hours ago

