Errors

Errors occur even in the best of systems, and we always try to provide sensible error codes to help you handle the error properly. All errors that you encounter in the All Aboard API will be GraphQL errors, optionally with an extensions property.

Extensions

Extensions are a GraphQL feature that allow us to add additional information to the error response. This is where we add the error code and any additional information which can help you identify the cause of the error.

json
{
  "errors": [
    {
      "message": "Message describing what went wrong",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["node", "field", 1, "name"],
      "extensions": {
        "code": "ERROR_CODE",
        "args": {
          "name": "value"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Message describing what went wrong",
      "locations": [{ "line": 6, "column": 7 }],
      "path": ["node", "field", 1, "name"],
      "extensions": {
        "code": "ERROR_CODE",
        "args": {
          "name": "value"
        }
      }
    }
  ]
}

Authentication and Authorization

UNAUTHORIZED

This happens when the api-key header is missing or the provided API key is invalid.

json
{
  "errors": [
    {
      "message": "Unauthorized",
      "extensions": {
        "code": "UNAUTHORIZED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Unauthorized",
      "extensions": {
        "code": "UNAUTHORIZED"
      }
    }
  ]
}

NOT_AUTHENTICATED

This happens when authentication is required but the request is not authenticated (e.g., when using JWT authentication).

json
{
  "errors": [
    {
      "message": "Not authenticated",
      "extensions": {
        "code": "NOT_AUTHENTICATED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Not authenticated",
      "extensions": {
        "code": "NOT_AUTHENTICATED"
      }
    }
  ]
}

USER_TOKEN_MISSING

This happens when a query that requires an end-user identity (the viewer query) is called with only an API key and no user token (JWT). Authenticate the request with a user JWT to resolve the viewer.

json
{
  "errors": [
    {
      "message": "This query requires a user token",
      "extensions": {
        "code": "USER_TOKEN_MISSING"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "This query requires a user token",
      "extensions": {
        "code": "USER_TOKEN_MISSING"
      }
    }
  ]
}

NOT_AUTHORIZED

This happens when the authenticated user does not have permission to perform the requested action.

json
{
  "errors": [
    {
      "message": "Not authorized",
      "extensions": {
        "code": "NOT_AUTHORIZED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Not authorized",
      "extensions": {
        "code": "NOT_AUTHORIZED"
      }
    }
  ]
}

FORBIDDEN

This happens when the target sales agent does not allow orders to be created on its behalf.

json
{
  "errors": [
    {
      "message": "Target agent does not allow orders",
      "extensions": {
        "code": "FORBIDDEN"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Target agent does not allow orders",
      "extensions": {
        "code": "FORBIDDEN"
      }
    }
  ]
}

Node and Resource Lookup

NOT_FOUND

This happens when a resource that is required by an operation cannot be found.

json
{
  "errors": [
    {
      "message": "Part was not found",
      "extensions": {
        "code": "NOT_FOUND"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Part was not found",
      "extensions": {
        "code": "NOT_FOUND"
      }
    }
  ]
}

INVALID_ID

This happens when an invalid ID format is provided.

json
{
  "errors": [
    {
      "message": "Invalid order id",
      "extensions": {
        "code": "INVALID_ID"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Invalid order id",
      "extensions": {
        "code": "INVALID_ID"
      }
    }
  ]
}

Validation

VALIDATION_ERROR

When working with Bookings or other inputs, the input data is validated and may fail validation. This error code is used when the input data is invalid. The extensions.validation property will contain the validation rule that failed.

json
{
  "errors": [
    {
      "message": "Passenger date of birth is required",
      "extensions": {
        "code": "VALIDATION_ERROR",
        "validation": "REQUIRED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Passenger date of birth is required",
      "extensions": {
        "code": "VALIDATION_ERROR",
        "validation": "REQUIRED"
      }
    }
  ]
}

Common validation values include:

  • REQUIRED - A required field is missing
  • MISSING_ARGUMENTS - Required arguments are missing

INVALID_ARGUMENT

This happens when an argument refers to a resource that cannot be resolved, such as a cost center that does not exist.

json
{
  "errors": [
    {
      "message": "Cost center not found",
      "extensions": {
        "code": "INVALID_ARGUMENT"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Cost center not found",
      "extensions": {
        "code": "INVALID_ARGUMENT"
      }
    }
  ]
}

Booking and Order Errors

BOOKING_NOT_FOUND

This happens when a mutation references a booking id that does not exist, for example a stale id or one taken from a different environment. Request a fresh booking and retry with its id.

json
{
  "errors": [
    {
      "message": "Booking not found",
      "extensions": {
        "code": "BOOKING_NOT_FOUND"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Booking not found",
      "extensions": {
        "code": "BOOKING_NOT_FOUND"
      }
    }
  ]
}

UNKNOWN

This can happen either when creating a booking or when prebooking tickets which happens when creating an order or a payment. This error code is used when we encounter an upstream error from one of our ticketing providers and the error is not recognized or when the error is not related to the booking or prebooking.

json
{
  "errors": [
    {
      "message": "Unable to process booking",
      "extensions": {
        "code": "UNKNOWN"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Unable to process booking",
      "extensions": {
        "code": "UNKNOWN"
      }
    }
  ]
}

NO_TICKETS

Tickets may sell out between the time you select a journey and the time you create a booking. This error code is used when one or more of the selected tickets are no longer available. In that case you should request a new JourneyOffer before trying to create a booking again.

You can use the extensions.args.originName and extensions.args.destinationName to determine which tickets are no longer available.

json
{
  "errors": [
    {
      "message": "One of the selected tickets are no longer available",
      "extensions": {
        "code": "NO_TICKETS",
        "args": {
          "originName": "London",
          "destinationName": "Paris"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "One of the selected tickets are no longer available",
      "extensions": {
        "code": "NO_TICKETS",
        "args": {
          "originName": "London",
          "destinationName": "Paris"
        }
      }
    }
  ]
}

COMPARTMENT_TYPE_UNAVAILABLE

The selected compartment type is not available for the selected journey. This error code is used when the selected compartment type is not available for the selected journey. In that case you should request a new JourneyOffer before trying to create a booking again.

json
{
  "errors": [
    {
      "message": "The selected compartment type is not available",
      "extensions": {
        "code": "COMPARTMENT_TYPE_UNAVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The selected compartment type is not available",
      "extensions": {
        "code": "COMPARTMENT_TYPE_UNAVAILABLE"
      }
    }
  ]
}

BOOKING_ALREADY_USED

Due to technical limitations with certain ticketing providers, some bookings (depending on the underlying operator) can only be used once. This means that if you try to create an order or a payment which then fails, the booking cannot be reused to perform the same action again. In that case you should create a new booking and try again.

json
{
  "errors": [
    {
      "message": "This booking cannot be used again",
      "extensions": {
        "code": "BOOKING_ALREADY_USED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "This booking cannot be used again",
      "extensions": {
        "code": "BOOKING_ALREADY_USED"
      }
    }
  ]
}

BOOKING_UNUSABLE

The booking cannot be completed, and retrying it will keep failing: the ticketing provider has left the underlying reservation in a state it can no longer act on. Unlike BOOKING_ALREADY_USED, this is not about reusing a booking that already did its job — this booking never completed and never will. Start a new journey search and create a new booking; reusing the same search results may hand you the same broken reservation.

json
{
  "errors": [
    {
      "message": "This booking can no longer be completed. Please start a new search.",
      "extensions": {
        "code": "BOOKING_UNUSABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "This booking can no longer be completed. Please start a new search.",
      "extensions": {
        "code": "BOOKING_UNUSABLE"
      }
    }
  ]
}

PRICE_CHANGED

The price has changed since the selection was made. You should request a new JourneyOffer before trying to create a booking again.

json
{
  "errors": [
    {
      "message": "The price has changed since the selection was made",
      "extensions": {
        "code": "PRICE_CHANGED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The price has changed since the selection was made",
      "extensions": {
        "code": "PRICE_CHANGED"
      }
    }
  ]
}

SEAT_UNAVAILABLE

The desired seat is not available for booking.

json
{
  "errors": [
    {
      "message": "The desired seat is not available",
      "extensions": {
        "code": "SEAT_UNAVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The desired seat is not available",
      "extensions": {
        "code": "SEAT_UNAVAILABLE"
      }
    }
  ]
}

NOT_ENOUGH_FUNDS

This happens when trying to create an order but there are not enough funds in the wallet.

json
{
  "errors": [
    {
      "message": "Not enough funds in wallet",
      "extensions": {
        "code": "NOT_ENOUGH_FUNDS"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Not enough funds in wallet",
      "extensions": {
        "code": "NOT_ENOUGH_FUNDS"
      }
    }
  ]
}

ORDER_LOCKED

The order is locked by another operation and cannot be modified at this time.

json
{
  "errors": [
    {
      "message": "Order is locked by other operation.",
      "extensions": {
        "code": "ORDER_LOCKED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Order is locked by other operation.",
      "extensions": {
        "code": "ORDER_LOCKED"
      }
    }
  ]
}

MISSING_CONTACT_PERSON

Exactly one passenger must be marked as the contact person. This error occurs when no passenger has contactPerson set to true.

json
{
  "errors": [
    {
      "message": "One person must be assigned as the contact person",
      "extensions": {
        "code": "MISSING_CONTACT_PERSON"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "One person must be assigned as the contact person",
      "extensions": {
        "code": "MISSING_CONTACT_PERSON"
      }
    }
  ]
}

MULTIPLE_CONTACT_PERSONS

Only one passenger can be the contact person. This error occurs when more than one passenger has contactPerson set to true.

json
{
  "errors": [
    {
      "message": "Only one person can be assigned as the contact person",
      "extensions": {
        "code": "MULTIPLE_CONTACT_PERSONS"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Only one person can be assigned as the contact person",
      "extensions": {
        "code": "MULTIPLE_CONTACT_PERSONS"
      }
    }
  ]
}

RESERVATION_UNAVAILABLE

A seat reservation for part of the journey could not be confirmed. You should request a new JourneyOffer before trying to create a booking again.

json
{
  "errors": [
    {
      "message": "A seat reservation for part of this journey could not be confirmed",
      "extensions": {
        "code": "RESERVATION_UNAVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "A seat reservation for part of this journey could not be confirmed",
      "extensions": {
        "code": "RESERVATION_UNAVAILABLE"
      }
    }
  ]
}

SELECTED_OFFER_UNAVAILABLE

A selected offer is no longer available. You should request a new JourneyOffer before trying to create a booking again.

json
{
  "errors": [
    {
      "message": "A selected offer is no longer available. Please try with a new booking.",
      "extensions": {
        "code": "SELECTED_OFFER_UNAVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "A selected offer is no longer available. Please try with a new booking.",
      "extensions": {
        "code": "SELECTED_OFFER_UNAVAILABLE"
      }
    }
  ]
}

TICKET_SUPPLIER_FAILURE

The ticket supplier's own booking system rejected or failed the request. This is usually transient, so the same booking can be retried.

json
{
  "errors": [
    {
      "message": "Our ticket supplier failed to complete the booking.",
      "extensions": {
        "code": "TICKET_SUPPLIER_FAILURE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Our ticket supplier failed to complete the booking.",
      "extensions": {
        "code": "TICKET_SUPPLIER_FAILURE"
      }
    }
  ]
}

INVALID_OFFER

One or more of the selected offer ids are invalid or could not be matched to the journey.

json
{
  "errors": [
    {
      "message": "Invalid offer id: ...",
      "extensions": {
        "code": "INVALID_OFFER"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Invalid offer id: ...",
      "extensions": {
        "code": "INVALID_OFFER"
      }
    }
  ]
}

OFFER_SET_INCOMPLETE

Some offers cannot be booked on their own: they belong to a set that spans several segment collections of a journey. A UK return fare, for example, is priced as a whole but appears as an offer on one direction and a companion offer at no extra cost on the other. A journey that is only sold whole shares one set across every offer of every collection. Either way the rule is the same: select an offer from the set for every collection it covers, or nothing from it at all. This error means a collection the set covers is not getting an offer from it.

There are two ways out — complete the set, or drop it — and which one you want depends on what you meant to book. To keep the set, select an offer from it for the collection the message names — on a journey sold whole, that means booking every collection it covers. To drop the set, select an offer outside it for every collection of it you book. That second way out is not always available: where a collection offers nothing outside the set, there is nothing to select in the set's place, so complete the set rather than retrying without it. See Offer Sets.

The message names the collection by where it goes — it calls it a leg — and says what is wrong with it: it is not in the booking at all, it is in the booking with no offer selected, or it is booked with an offer from outside the set. The first of those only reaches you from createBooking; updating a booking's selections cannot leave out a collection the booking already holds.

Use extensions.args.offerSetIds to identify the set, matching it against the memberOf.id of the offers you were shown. The message never names a set id or an offer id — offer ids are rewritten for you, so the id we hold is not the one you hold.

If a request breaks more than one set, you get one error per set rather than only the first. Each error names one collection of its set, so a set missing several is reported one at a time as you fix them; cover every collection the set spans in one call instead.

json
{
  "errors": [
    {
      "message": "This offer set covers the London Euston – Edinburgh leg, which is not in this booking. Select an offer from the set for every leg it covers, or select nothing from it.",
      "extensions": {
        "code": "OFFER_SET_INCOMPLETE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "This offer set covers the London Euston – Edinburgh leg, which is not in this booking. Select an offer from the set for every leg it covers, or select nothing from it.",
      "extensions": {
        "code": "OFFER_SET_INCOMPLETE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}

When the collection is in the booking but was left without an offer, the message says so instead:

json
{
  "errors": [
    {
      "message": "This offer set covers the Edinburgh – London Euston leg, which has no offer selected. Select an offer from the set for every leg it covers, or select nothing from it.",
      "extensions": {
        "code": "OFFER_SET_INCOMPLETE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "This offer set covers the Edinburgh – London Euston leg, which has no offer selected. Select an offer from the set for every leg it covers, or select nothing from it.",
      "extensions": {
        "code": "OFFER_SET_INCOMPLETE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}

And when it was given an offer from outside the set:

json
{
  "errors": [
    {
      "message": "This offer set covers the Edinburgh – London Euston leg, which is booked with an offer outside the set. Select an offer from the set for every leg it covers, or select nothing from it.",
      "extensions": {
        "code": "OFFER_SET_INCOMPLETE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "This offer set covers the Edinburgh – London Euston leg, which is booked with an offer outside the set. Select an offer from the set for every leg it covers, or select nothing from it.",
      "extensions": {
        "code": "OFFER_SET_INCOMPLETE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}

OFFER_SET_UNAVAILABLE

You selected an offer belonging to a set, but the other parts of the journey that set covers are no longer on offer. The set can no longer be completed, so select an offer outside the set for the collection the message names. Where that collection has nothing else on offer, request a new JourneyOffer before trying to create a booking again.

Only booking creation returns this code; updating a booking's selections does not.

This is not OFFER_SET_INCOMPLETE: there is no missing offer left to select. Use extensions.args.offerSetIds to identify the set, matching it against the memberOf.id of the offers you were shown. You get one error per such set.

json
{
  "errors": [
    {
      "message": "The other legs this offer set covers are no longer on offer, so it cannot be booked. Select an offer outside the set for the London Euston – Edinburgh leg, or search this journey again.",
      "extensions": {
        "code": "OFFER_SET_UNAVAILABLE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The other legs this offer set covers are no longer on offer, so it cannot be booked. Select an offer outside the set for the London Euston – Edinburgh leg, or search this journey again.",
      "extensions": {
        "code": "OFFER_SET_UNAVAILABLE",
        "args": {
          "offerSetIds": ["offer_set_01k2yq..."]
        }
      }
    }
  ]
}

OFFER_SET_CONFLICT

You selected offers belonging to two different sets that cover the same collection. Neither set can be completed without the other losing a collection, so the combination is not bookable. Select offers from one set only.

extensions.args.offerSetIds holds both sets — they are peers, so the order between them carries no meaning. You get one error per conflicting pair.

json
{
  "errors": [
    {
      "message": "Two offer sets both cover the London Euston – Edinburgh leg and cannot be booked together.",
      "extensions": {
        "code": "OFFER_SET_CONFLICT",
        "args": {
          "offerSetIds": ["offer_set_01k2yq...", "offer_set_01k2yr..."]
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Two offer sets both cover the London Euston – Edinburgh leg and cannot be booked together.",
      "extensions": {
        "code": "OFFER_SET_CONFLICT",
        "args": {
          "offerSetIds": ["offer_set_01k2yq...", "offer_set_01k2yr..."]
        }
      }
    }
  ]
}

NOT_OPTIONAL

This happens when trying to toggle a booking part that is not optional and therefore cannot be added or removed.

json
{
  "errors": [
    {
      "message": "Part is not optional and cannot be toggled",
      "extensions": {
        "code": "NOT_OPTIONAL"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Part is not optional and cannot be toggled",
      "extensions": {
        "code": "NOT_OPTIONAL"
      }
    }
  ]
}

INVALID_ANCILLARY_PASSENGER

The passengerId provided for an ancillary does not match any passenger on the booking.

json
{
  "errors": [
    {
      "message": "Ancillary passenger_id does not match any passenger on the booking",
      "extensions": {
        "code": "INVALID_ANCILLARY_PASSENGER"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Ancillary passenger_id does not match any passenger on the booking",
      "extensions": {
        "code": "INVALID_ANCILLARY_PASSENGER"
      }
    }
  ]
}

INVALID_ANCILLARY_PASSENGER_FOR_OFFER

The ancillary cannot be sold to the given passenger because they are not in the offer's set of applicable passengers.

json
{
  "errors": [
    {
      "message": "Ancillary cannot be sold to passenger — not in the offer's applicable passenger set",
      "extensions": {
        "code": "INVALID_ANCILLARY_PASSENGER_FOR_OFFER"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Ancillary cannot be sold to passenger — not in the offer's applicable passenger set",
      "extensions": {
        "code": "INVALID_ANCILLARY_PASSENGER_FOR_OFFER"
      }
    }
  ]
}

OFFER_NOT_FOUND

The offer id given to setTicketDelivery matches no offer. The id is an Offer.id, taken from the booking or from the offers you were shown.

json
{
  "errors": [
    {
      "message": "Offer was not found",
      "extensions": {
        "code": "OFFER_NOT_FOUND"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Offer was not found",
      "extensions": {
        "code": "OFFER_NOT_FOUND"
      }
    }
  ]
}

UNAVAILABLE_TICKET_DELIVERY_METHOD

The delivery method given to setTicketDelivery is not one the offer can be issued with. Pick one of the methods in that offer's ticketDelivery.availableOptions.

json
{
  "errors": [
    {
      "message": "That ticket delivery method is not available for this offer",
      "extensions": {
        "code": "UNAVAILABLE_TICKET_DELIVERY_METHOD"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "That ticket delivery method is not available for this offer",
      "extensions": {
        "code": "UNAVAILABLE_TICKET_DELIVERY_METHOD"
      }
    }
  ]
}

PAYMENT_METHOD_NOT_ALLOWED

No payment method is both configured on the cost centers and allowed for the API key used to create the order.

json
{
  "errors": [
    {
      "message": "No payment method is both configured on the cost centers and allowed for this API key",
      "extensions": {
        "code": "PAYMENT_METHOD_NOT_ALLOWED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "No payment method is both configured on the cost centers and allowed for this API key",
      "extensions": {
        "code": "PAYMENT_METHOD_NOT_ALLOWED"
      }
    }
  ]
}

WALLET_NOT_AVAILABLE

The cost center is configured for wallet payments but has no wallet in the order's currency.

json
{
  "errors": [
    {
      "message": "The cost center is configured for wallet payments but has no wallet in the order currency",
      "extensions": {
        "code": "WALLET_NOT_AVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The cost center is configured for wallet payments but has no wallet in the order currency",
      "extensions": {
        "code": "WALLET_NOT_AVAILABLE"
      }
    }
  ]
}

Passenger Validation Errors

INVALID_AGE

The provided age doesn't match the passenger birth dates.

json
{
  "errors": [
    {
      "message": "The provided age doesn't match the passenger birth dates",
      "extensions": {
        "code": "INVALID_AGE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The provided age doesn't match the passenger birth dates",
      "extensions": {
        "code": "INVALID_AGE"
      }
    }
  ]
}

AGE_CATEGORY_CHANGED

A passenger birth date has changed in a way that the passenger type changed from search. You can use extension.args.passengerId to identify which passenger the error pertains to.

json
{
  "errors": [
    {
      "message": "A passenger birth date has changed in a way that the passenger type changed from search",
      "extensions": {
        "code": "AGE_CATEGORY_CHANGED",
        "args": {
          "passengerId": "6d807972-e779-44a7-a8de-62225ef57ac3"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "A passenger birth date has changed in a way that the passenger type changed from search",
      "extensions": {
        "code": "AGE_CATEGORY_CHANGED",
        "args": {
          "passengerId": "2d515209-68c8-4ba7-92af-466a60c6fcb3"
        }
      }
    }
  ]
}

PASSENGER_MISMATCH

The passengers you create the booking for aren't the passengers the offers were priced for. They are compared one by one, in the order you send them, on passenger type, age and travel card codes — a card's identifier is not part of the comparison, and the order of a passenger's cards doesn't matter. Price the journey again for the passengers you mean to book, and create the booking from the offers that come back.

json
{
  "errors": [
    {
      "message": "Provided passenger placeholders do not match the passengers the offers were searched for (type, age or travel cards)",
      "extensions": {
        "code": "PASSENGER_MISMATCH"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Provided passenger placeholders do not match the passengers the offers were searched for (type, age or travel cards)",
      "extensions": {
        "code": "PASSENGER_MISMATCH"
      }
    }
  ]
}

PASSENGER_FIELD_MISSING

A required passenger field is missing. The extensions.args.field property will contain the name of the missing field and the extensions.args.passengerId can help you identify the passenger.

json
{
  "errors": [
    {
      "message": "Missing passenger field birthDate",
      "extensions": {
        "code": "PASSENGER_FIELD_MISSING",
        "args": {
          "field": "birthDate",
          "passengerId": "22977c4e-8e48-4091-b3ac-59dba36470a7"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Missing passenger field birthDate",
      "extensions": {
        "code": "PASSENGER_FIELD_MISSING",
        "args": {
          "field": "birthDate",
          "passengerId": "27854606-a7be-4d9c-928d-ae0e59917fbc"
        }
      }
    }
  ]
}

PASSENGER_VALIDATION_FAILED

Passenger validation failed. Additional details may be provided in extensions.args.

json
{
  "errors": [
    {
      "message": "Passenger last name must be between 2 and 15 characters long",
      "extensions": {
        "code": "PASSENGER_VALIDATION_FAILED",
        "args": {
          "validation": "LENGTH",
          "field": "lastName",
          "min": 2,
          "max": 15,
          "passengerId": "0dc3bdb7-2a69-4a51-8073-f8c1c89a084c"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Passenger last name must be between 2 and 15 characters long",
      "extensions": {
        "code": "PASSENGER_VALIDATION_FAILED",
        "args": {
          "validation": "LENGTH",
          "field": "lastName",
          "min": 2,
          "max": 15,
          "passengerId": "8f2c7b2d-c9bb-4eac-a393-ed47ab180720"
        }
      }
    }
  ]
}

UNKNOWN_PASSENGER_ERROR

An unknown error occurred while resolving passenger placeholders.

json
{
  "errors": [
    {
      "message": "Unknown passenger error",
      "extensions": {
        "code": "UNKNOWN_PASSENGER_ERROR"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Unknown passenger error",
      "extensions": {
        "code": "UNKNOWN_PASSENGER_ERROR"
      }
    }
  ]
}

DUPLICATE_PASSENGER_NAME

Two or more passengers share the same name, which some ticketing providers do not allow. The duplicated name is available in extensions.args.name.

json
{
  "errors": [
    {
      "message": "There are duplicates in the passenger names: John Doe",
      "extensions": {
        "code": "DUPLICATE_PASSENGER_NAME",
        "args": {
          "name": "John Doe"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "There are duplicates in the passenger names: John Doe",
      "extensions": {
        "code": "DUPLICATE_PASSENGER_NAME",
        "args": {
          "name": "John Doe"
        }
      }
    }
  ]
}

TRAVEL_CARD_FIELD_REQUIRED

A travel card attached to a passenger is missing a field this booking requires, typically the identifier of an Interrail Pass. Whether it is required depends on the operators and kinds of train in the booking. extensions.args.field names the field. Collect it and create the booking again with the same offer ids; nothing was booked. See Travel Cards.

json
{
  "errors": [
    {
      "message": "Travel card identifier is required.",
      "extensions": {
        "code": "TRAVEL_CARD_FIELD_REQUIRED",
        "args": {
          "field": "identifier"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Travel card identifier is required.",
      "extensions": {
        "code": "TRAVEL_CARD_FIELD_REQUIRED",
        "args": {
          "field": "identifier"
        }
      }
    }
  ]
}

TRAVEL_CARDS_IMMUTABLE

The travelCards sent for a passenger on updateBooking differ from the ones that passenger already holds. A booking is priced on the cards its passengers hold, so cards are set when pricing the journey offer and creating the booking. They can't be changed afterwards. Omit travelCards when updating passengers; sending back the cards the passenger already carries is accepted as a no-op. None of the passenger changes in the call are saved. See Travel Cards.

json
{
  "errors": [
    {
      "message": "Travel cards can't be changed on an existing booking. Search again with the right cards and create a new booking.",
      "extensions": {
        "code": "TRAVEL_CARDS_IMMUTABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Travel cards can't be changed on an existing booking. Search again with the right cards and create a new booking.",
      "extensions": {
        "code": "TRAVEL_CARDS_IMMUTABLE"
      }
    }
  ]
}

Rail Pass Errors

INVALID_COUNTRY_FOR_PASS

The selected type of pass (Eurail or Interrail) is not valid in the passenger's country of residence.

json
{
  "errors": [
    {
      "message": "The selected type of pass (Eurail or Interrail) is not valid in the passenger's country of residence",
      "extensions": {
        "code": "INVALID_COUNTRY_FOR_PASS"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The selected type of pass (Eurail or Interrail) is not valid in the passenger's country of residence",
      "extensions": {
        "code": "INVALID_COUNTRY_FOR_PASS"
      }
    }
  ]
}

RESIDENCE_MATCHES_PASS_COUNTRY

A One Country Pass cannot be used by a passenger whose country of residence is the same as the pass's country. Choose a Global Pass or a pass for a different country.

json
{
  "errors": [
    {
      "message": "A One Country Pass can't be used in the passenger's own country of residence. Choose a Global Pass or a pass for a different country.",
      "extensions": {
        "code": "RESIDENCE_MATCHES_PASS_COUNTRY"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "A One Country Pass can't be used in the passenger's own country of residence. Choose a Global Pass or a pass for a different country.",
      "extensions": {
        "code": "RESIDENCE_MATCHES_PASS_COUNTRY"
      }
    }
  ]
}

NO_COUNTRY_PROVIDED

No country of residence was provided for a passenger.

json
{
  "errors": [
    {
      "message": "No country of residence was provided",
      "extensions": {
        "code": "NO_COUNTRY_PROVIDED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "No country of residence was provided",
      "extensions": {
        "code": "NO_COUNTRY_PROVIDED"
      }
    }
  ]
}

CAMPAIGN_CLOSED

The selected campaign deal is no longer available.

json
{
  "errors": [
    {
      "message": "The selected campaign deal is no longer available",
      "extensions": {
        "code": "CAMPAIGN_CLOSED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The selected campaign deal is no longer available",
      "extensions": {
        "code": "CAMPAIGN_CLOSED"
      }
    }
  ]
}

CAMPAIGN_NOT_FOUND

The campaign with the given ID does not exist.

json
{
  "errors": [
    {
      "message": "The campaign with the given id does not exist",
      "extensions": {
        "code": "CAMPAIGN_NOT_FOUND"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The campaign with the given id does not exist",
      "extensions": {
        "code": "CAMPAIGN_NOT_FOUND"
      }
    }
  ]
}

DATE_OF_BIRTH_AND_PASS_TYPE_INCOMPATIBLE

The selected pass type is not compatible with the given birth date.

json
{
  "errors": [
    {
      "message": "The selected pass type is not compatible with the given birth date",
      "extensions": {
        "code": "DATE_OF_BIRTH_AND_PASS_TYPE_INCOMPATIBLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The selected pass type is not compatible with the given birth date",
      "extensions": {
        "code": "DATE_OF_BIRTH_AND_PASS_TYPE_INCOMPATIBLE"
      }
    }
  ]
}

PASS_UNAVAILABLE

The selected pass is no longer available.

json
{
  "errors": [
    {
      "message": "The selected pass is not available",
      "extensions": {
        "code": "PASS_UNAVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The selected pass is not available",
      "extensions": {
        "code": "PASS_UNAVAILABLE"
      }
    }
  ]
}

Journey Search Errors

TRAVEL_CARD_FIELD_REQUIRED

A required travel card field is missing from the search. The missing field is available in extensions.args.field.

json
{
  "errors": [
    {
      "message": "Travel card number is required.",
      "extensions": {
        "code": "TRAVEL_CARD_FIELD_REQUIRED",
        "args": {
          "field": "number"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Travel card number is required.",
      "extensions": {
        "code": "TRAVEL_CARD_FIELD_REQUIRED",
        "args": {
          "field": "number"
        }
      }
    }
  ]
}

PLACEHOLDER_PASS_CODES_UNAVAILABLE

Tickets for the requested route could not be looked up at the moment. You should try again later.

json
{
  "errors": [
    {
      "message": "Unable to look up tickets for this route at the moment. Please try again later.",
      "extensions": {
        "code": "PLACEHOLDER_PASS_CODES_UNAVAILABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Unable to look up tickets for this route at the moment. Please try again later.",
      "extensions": {
        "code": "PLACEHOLDER_PASS_CODES_UNAVAILABLE"
      }
    }
  ]
}

Timetable Errors

OUTSIDE_TIMETABLE

Just like with ticket availability, operators release new timetables at different intervals. Most often this happens around the end of the year when both booking horizons and timetable availability may be shorter than usual.

json
{
  "errors": [
    {
      "message": "The timetable for the given date is not available yet",
      "extensions": {
        "code": "OUTSIDE_TIMETABLE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The timetable for the given date is not available yet",
      "extensions": {
        "code": "OUTSIDE_TIMETABLE"
      }
    }
  ]
}

DATE_IN_PAST

The search date is in the past.

json
{
  "errors": [
    {
      "message": "Search date is in the past",
      "extensions": {
        "code": "DATE_IN_PAST"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Search date is in the past",
      "extensions": {
        "code": "DATE_IN_PAST"
      }
    }
  ]
}

LOCATIONS_EQUAL

Equal origin and destination locations were provided.

json
{
  "errors": [
    {
      "message": "Equal origin and destination given",
      "extensions": {
        "code": "LOCATIONS_EQUAL"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Equal origin and destination given",
      "extensions": {
        "code": "LOCATIONS_EQUAL"
      }
    }
  ]
}

LOCATION_NOT_FOUND

A location with the given UID could not be resolved.

json
{
  "errors": [
    {
      "message": "Could not resolve location e:...",
      "extensions": {
        "code": "LOCATION_NOT_FOUND"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Could not resolve location e:...",
      "extensions": {
        "code": "LOCATION_NOT_FOUND"
      }
    }
  ]
}

RATE_LIMITED

The request has been rate limited. See the rateLimits field of SalesAgent for details.

json
{
  "errors": [
    {
      "message": "You have been rate limited.",
      "extensions": {
        "code": "RATE_LIMITED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "You have been rate limited.",
      "extensions": {
        "code": "RATE_LIMITED"
      }
    }
  ]
}

Refund Errors

ALREADY_REFUNDED

The order is already refunded.

json
{
  "errors": [
    {
      "message": "Order is already refunded.",
      "extensions": {
        "code": "ALREADY_REFUNDED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Order is already refunded.",
      "extensions": {
        "code": "ALREADY_REFUNDED"
      }
    }
  ]
}

REFUND_ALREADY_IN_PROGRESS

A refund is already in progress for this order.

json
{
  "errors": [
    {
      "message": "A refund is already in progress.",
      "extensions": {
        "code": "REFUND_ALREADY_IN_PROGRESS"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "A refund is already in progress.",
      "extensions": {
        "code": "REFUND_ALREADY_IN_PROGRESS"
      }
    }
  ]
}

REFUND_EXPIRED

The refund has expired.

json
{
  "errors": [
    {
      "message": "Refund has expired.",
      "extensions": {
        "code": "REFUND_EXPIRED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Refund has expired.",
      "extensions": {
        "code": "REFUND_EXPIRED"
      }
    }
  ]
}

REFUND_INVALID

The refund is invalid.

json
{
  "errors": [
    {
      "message": "Refund is invalid.",
      "extensions": {
        "code": "REFUND_INVALID"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Refund is invalid.",
      "extensions": {
        "code": "REFUND_INVALID"
      }
    }
  ]
}

UNEXPECTED_REFUND_STATE

The refund is in an unexpected state and cannot be processed.

json
{
  "errors": [
    {
      "message": "Refund is in an unexpected state",
      "extensions": {
        "code": "UNEXPECTED_REFUND_STATE"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Refund is in an unexpected state",
      "extensions": {
        "code": "UNEXPECTED_REFUND_STATE"
      }
    }
  ]
}

NO_ITEMS_SELECTED

No items were selected for the refund.

json
{
  "errors": [
    {
      "message": "No items selected for refund",
      "extensions": {
        "code": "NO_ITEMS_SELECTED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "No items selected for refund",
      "extensions": {
        "code": "NO_ITEMS_SELECTED"
      }
    }
  ]
}

WALLET_CREDIT_FAILED

The refund was processed successfully but the wallet could not be credited. You should contact support.

json
{
  "errors": [
    {
      "message": "Refund was processed successfully but failed to credit the wallet. Please contact support.",
      "extensions": {
        "code": "WALLET_CREDIT_FAILED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Refund was processed successfully but failed to credit the wallet. Please contact support.",
      "extensions": {
        "code": "WALLET_CREDIT_FAILED"
      }
    }
  ]
}

Other Errors

NO_MATCH

Unable to find a matching trip.

json
{
  "errors": [
    {
      "message": "Unable to find a matching trip",
      "extensions": {
        "code": "NO_MATCH"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Unable to find a matching trip",
      "extensions": {
        "code": "NO_MATCH"
      }
    }
  ]
}

VALIDATION_FAILED

Order validation failed. This is a general validation error that may occur during order creation.

json
{
  "errors": [
    {
      "message": "Order validation failed",
      "extensions": {
        "code": "VALIDATION_FAILED"
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Order validation failed",
      "extensions": {
        "code": "VALIDATION_FAILED"
      }
    }
  ]
}

INTERNAL_ERROR

Something failed on our side. The failure has been reported to us, so there is nothing to correct in the request — retrying it later is the only useful response. Quoting args.requestId in a support request lets us find the exact failure. It is null for operations sent over a websocket, which have no request id.

The message is always the same fixed sentence and never describes the underlying failure.

json
{
  "errors": [
    {
      "message": "Something went wrong on our side. Please try again in a moment.",
      "extensions": {
        "code": "INTERNAL_ERROR",
        "args": {
          "requestId": "F9-8OGZUbvcJmDsAAAmB"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "Something went wrong on our side. Please try again in a moment.",
      "extensions": {
        "code": "INTERNAL_ERROR",
        "args": {
          "requestId": "F9-8OGZUbvcJmDsAAAmB"
        }
      }
    }
  ]
}

TIMEOUT

An operation waited too long for something behind it — usually a rail provider — and gave up. Whether the work it started completed anyway is unknown, so re-read the booking or order before retrying rather than assuming nothing happened. As with INTERNAL_ERROR, quote args.requestId in a support request; it is null over a websocket.

json
{
  "errors": [
    {
      "message": "The request timed out. Please try again.",
      "extensions": {
        "code": "TIMEOUT",
        "args": {
          "requestId": "F9-8OGZUbvcJmDsAAAmB"
        }
      }
    }
  ]
}
{
  "errors": [
    {
      "message": "The request timed out. Please try again.",
      "extensions": {
        "code": "TIMEOUT",
        "args": {
          "requestId": "F9-8OGZUbvcJmDsAAAmB"
        }
      }
    }
  ]
}