Errors
Every error response from the jtWMS API, 4xx or 5xx, is an
RFC 9457 problem details object, sent with the content
type application/problem+json.
The error envelope
Section titled “The error envelope”HTTP/1.1 409 ConflictContent-Type: application/problem+jsonX-Correlation-Id: 3f2504e0-4f89-11d3-9a0c-0305e82c3301
{ "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10", "title": "Conflict", "status": 409, "detail": "A product with SKU 'PAL-0042' already exists (SKUs are compared ignoring case).", "errorCode": "sku_conflict", "traceId": "00-6f1c0a9d2b6e4c1f8a3b5d7e9f0a1b2c-4d5e6f7a8b9c0d1e-00", "correlationId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301"}| Member | Present | Meaning |
|---|---|---|
status |
Always | The HTTP status code. |
title |
Always | A short summary of the status, such as Not Found or Conflict. |
type |
Usually | A URI for the problem type. By default, the RFC 9110 section for the status. |
detail |
When there is a message | A human-readable explanation of this error, suitable to show to a user. |
errorCode |
When the error has one | A stable, machine-readable code. See Error codes. |
traceId |
Always | The request’s trace identifier. |
correlationId |
Always | The request’s correlation ID. See Correlation IDs. |
Some errors add members that help you act on them, such as maxApiKeys, childIds or barcodes.
They sit beside the standard members, in camelCase.
Validation errors
Section titled “Validation errors”A request that fails validation gets 400 Bad Request with an errors member. Its keys are the
paths of the invalid fields, in PascalCase as the server names them, including array indexes; its
values are lists of messages.
{ "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1", "title": "One or more validation errors occurred.", "status": 400, "errors": { "Name": ["'Name' must not be empty."], "UnitsOfMeasure[1].Barcodes[0].Value": ["'Value' must be a GTIN of 8, 12, 13 or 14 digits with a valid check digit."] }, "traceId": "00-6f1c0a9d2b6e4c1f8a3b5d7e9f0a1b2c-4d5e6f7a8b9c0d1e-00", "correlationId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301"}Map the keys to your own fields case-insensitively. A validation error can also carry an
errorCode, as the API key scope errors do.
Common statuses
Section titled “Common statuses”| Status | Meaning |
|---|---|
400 |
The request is invalid. Fix it before retrying. |
401 |
The request isn’t authenticated, or its token or key is no longer valid. See Authentication. |
403 |
The caller lacks the permission the endpoint needs, or the tenant’s plan lacks the feature. See Permissions. |
404 |
The resource doesn’t exist, has been deleted, or belongs to another tenant. These cases aren’t told apart. |
409 |
The request conflicts with the resource’s current state. See Concurrency and deletes. |
422 |
The request is well formed but can’t be processed (sign-up with a registered email). |
429 |
A rate limit was exceeded. See Rate limits. |
500 |
An unexpected error. The detail doesn’t include internal information; quote the correlationId to support. |
502, 504 |
jtWMS couldn’t reach the service that handles the route, or it didn’t answer in time. Retry later. |
503 |
A dependency is briefly unavailable. Retry after the Retry-After seconds. |
Error codes
Section titled “Error codes”errorCode |
Status | Meaning |
|---|---|---|
token_revoked |
401 | The user’s access changed since the token was issued. Refresh the session, or sign in again if the refresh fails. |
invalid_api_key |
401 | The API key is unknown, revoked or expired, or its tenant is inactive. |
auth_unavailable |
503 | The API key couldn’t be checked just now. Retry after Retry-After (5 seconds). |
feature_not_entitled |
403 | The tenant’s plan doesn’t include the feature the route needs. |
permission_not_held |
403 | A role, invite or role change would hand out permissions you don’t hold. They are listed in permissions. |
burst_limit_exceeded |
429 | Too many requests in a short period. Retry after Retry-After. |
rate_limit_exceeded |
429 | The tenant’s daily request quota is used up. Retry after Retry-After. |
concurrency_conflict |
409 | Another request changed the same data at the same time. Nothing was saved. Re-read and retry. |
api_key_permission_unknown |
400 | A requested API key permission isn’t registered or is inactive. |
api_key_permission_not_held |
400 | You don’t hold a permission you asked to give an API key. |
api_key_limit_reached |
409 | The tenant has as many API keys as its plan allows (maxApiKeys). |
system_role_immutable |
409 | System roles can’t be deleted, renamed or edited. Copy the role instead. |
user_inactive |
409 | The user is deactivated. Reactivate them first. |
invite_role_unknown |
400 | An invite names a role that isn’t one of the tenant’s roles. |
INVITE_NOT_FOUND, INVITE_INVALID |
404 | The invite link is unknown, expired, revoked or already used. |
USER_ALREADY_EXISTS |
409 | A user with this email already exists. |
email_in_use |
409 | An invite names, or is accepted for, an email that belongs to a jtWMS account elsewhere. |
invite_daily_limit |
429 | The organisation has sent its daily limit of invites (200 in 24 hours). Nothing was saved. |
sandbox_not_found |
404 | The organisation has no sandbox. |
sandbox_exists |
409 | The organisation already has a sandbox. Reset it to start again. |
sandbox_reset_limit |
429 | The organisation has created as many sandboxes today (creates and resets) as it can. |
not_allowed_in_sandbox |
409 | The action can’t be taken inside a sandbox: inviting people, changing plan, or managing a sandbox. |
sandbox_plan_reserved |
409 | A plan or add-on change would give a sandbox other entitlements than the sandbox plan’s, or move another tenant onto it. |
EMAIL_ALREADY_EXISTS |
422 | Sign-up with an email that is already registered. |
reset_token_invalid |
400 | The password reset link is invalid or has expired. Ask for a new one. |
product_not_found |
404 | No product matches the lookup, or an inventory write names a product that isn’t known (listed in productIds). |
product_already_active |
409 | The product is already active. |
product_already_inactive |
409 | The product is already inactive. |
sku_conflict |
409 | Another product already has this SKU (ignoring case). |
barcode_conflict |
409 | Barcodes in the request are already assigned to another product. They are listed in barcodes. |
facility_not_found |
404 | An inventory request names a facility that isn’t known. |
location_not_found |
404 | An inventory write names a location that isn’t known or is in another facility (listed in locationIds). |
position_not_found |
404 | The stock position isn’t in this facility, or was emptied. For a move, hold or release by serial numbers, the serials not on hand in the facility are listed in serials. |
lpn_not_found |
404 | The license plate isn’t in this facility, or was deleted (listed in lpnIds). |
code_not_found |
404 | A lookup’s code is no license plate, location, barcode or SKU in this facility. |
transaction_not_found |
404 | The stock transaction isn’t in this facility. |
allocation_not_found |
404 | The allocation isn’t in this facility. |
allocation_line_not_found |
404 | A pick names a line that isn’t the allocation’s, or serial numbers no line of it holds (listed in serials). |
lpn_nesting_invalid |
400 | A license plate can’t go there: only a case or tote sits on another license plate, and only on a pallet. The field is listed in errors. |
nothing_to_move |
400 | The move’s or pick’s target is where the stock or license plate already is. |
stock_rules_violated |
400 | A line breaks its product’s rules: an unknown unit of measure, a missing or unwanted lot, expiry date or serials, or a quantity too large. The fields are listed in errors. |
product_blocked, location_blocked, facility_blocked |
409 | Stock can’t be received or adjusted into a product, location or facility that isn’t active, and nothing can be moved or picked into, or a license plate created at, a location or facility that isn’t. Nothing of a product that isn’t active, or in a facility that isn’t, can be allocated. The reasons are in blockedReasons. |
lpn_code_conflict |
409 | Another license plate in the facility already has this code (ignoring case). |
lpn_not_empty |
409 | The license plate, or one on it, still holds stock (listed in lpnIds). Move or adjust the stock out first. |
lpn_location_mismatch |
409 | The license plate named isn’t at the location named with it (its locationId is included). |
lot_expiry_mismatch |
409 | The lot already exists with another expiry date (in expiryDate). |
serial_conflict |
409 | Serial numbers in the request are already on hand. They are listed in serials. |
insufficient_stock |
409 | An adjustment, move or hold would take a position below zero (its quantity is included), or an allocation asks for more than is available (its availableQuantity and requestedQuantity are included). |
stock_allocated |
409 | An adjustment, move or hold would take a position below its allocated quantity. |
stock_already_held |
409 | A hold names stock that is already quarantined or damaged (its stockStatus, or the serials, are included). Release it, then hold it again to change the hold. |
stock_not_held |
409 | A release names stock that isn’t held (its stockStatus, or the serials, are included). |
pick_exceeds_allocation |
409 | A pick asks for more than its allocation line has left to pick (its unpickedQuantity, or the serials already picked, are included). |
allocation_released |
409 | The allocation was released: it can’t be picked or released again. |
OAuth endpoints
Section titled “OAuth endpoints”The token and revocation endpoints, /connect/token and /connect/revoke, follow the OAuth 2.0
error format that OAuth clients expect, not problem details:
{ "error": "invalid_grant", "error_description": "The email or password is incorrect."}Reporting a problem
Section titled “Reporting a problem”When you contact support about an error, quote its correlationId. It is also in the response’s
X-Correlation-Id header, and it identifies the request in jtWMS’s logs. See
Correlation IDs.