This page outlines the canonical error codes that you must return in your API
responses when integrating with Google using the Universal Commerce Protocol
(UCP). Consistent error codes ensure clear communication and help Google handle
different scenarios appropriately.

When a business error occurs, your API should return a response message that
includes the appropriate `code` from the table. For some error codes, a specific
JSON structure is recommended for the `messages` array in the response. These
examples are provided in the [Error code examples](https://developers.google.com/merchant/ucp/guides/overview/error-codes#error-code-examples) section
below the table. In these examples, you should use the `path` field to provide
more specific information about the location of the error within the request or
response object.

> [!IMPORTANT]
> **Important:** You must strictly adhere to the published canonical codes and avoid generic codes such as `invalid`. Returning an unrecognized error code causes the Google UI to fall back to a generic "something went wrong" message, resulting in a poor checkout experience.

## Error Handling

How to report errors depends on the error type:

- **Protocol/Server Errors:**

  - Use standard HTTP status codes (e.g., 4xx for client errors, 5xx for server errors) for issues like malformed requests, authentication failures, or server unavailability.
  - Refer to the [UCP Specification](https://ucp.dev/latest/specification/overview/#error-handling) for details.
- **Business Logic Errors/Warnings:**

  - Return an **HTTP 200 OK** status. This includes payment declines and fraud rejections, even if your downstream payment gateway returns a 4xx or 5xx error.
  - Describe the issue within the `messages` array in the JSON response body.
  - Each object in the `messages` array must include:
    - `type`: `"error"` or `"warning"`
    - `code`: A standardized code from this guide. Don't use generic or unrecognized codes such as `"invalid"`.
    - `content`: A human-readable description.
    - `severity`: Required when `type` is `"error"`. This field explicitly indicates if the error is terminal (`unrecoverable`) or lets you prompt the buyer to correct the issue (`recoverable`), rather than relying on the error code itself.

> [!WARNING]
> **Warning:** Don't include personally identifiable information (PII) or sensitive personally identifiable information (SPII) in your error responses. This applies to both protocol errors and business logic errors.

## Message types: Error versus warning

The `type` field in the message array indicates the severity of the issue. UCP
defines two primary types:

- **`error`** : Indicates that the requested operation couldn't be completed. The platform or user will likely need to take action and try again. See [message-error
  specification](https://ucp.dev/latest/specification/checkout/#message-error).
  - The terminal nature of an error is determined by the `severity` field (`unrecoverable` or `recoverable`), not the error `code`.
- **`warning`** : Indicates that the operation was not blocked, but there's something noteworthy that should be communicated to the user. This doesn't halt the process but provides important context. See [message-warning
  specification](https://ucp.dev/latest/specification/checkout/#message-warning).

## Error code reference

| Error code | Recommended type | Description |
|---|---|---|
| `out_of_stock` | Error | Item is not available. This typically results in `ucp.status: "error"`. Use the `path` field to indicate the item index in multi-item checkouts. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#out_of_stock). |
| `item_unavailable` | Error | Item couldn't be found. This typically results in `ucp.status: "error"` for these item-related errors. |
| `item_ineligible` | Error | Item exists but cannot be purchased using UCP. |
| `quantity_invalid_limit_exceeded` | Error | The requested quantity exceeds the allowable limit. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#quantity_invalid_limit_exceeded). |
| `quantity_invalid_minimum_not_met` | Error | The requested quantity is below the minimum required. |
| `totals_changed` | Warning | The price or other totals have changed since the last step. Use the `path` field to indicate which total changed. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#totals_changed). |
| `totals_invalid_minimum_not_met` | Error | The order value does not meet the minimum requirement. |
| `missing_buyer_info` | Error | Required buyer information is missing. Use the `path` field to specify the missing field. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#missing_buyer_info). |
| `address_undeliverable` | Error | This is a standard UCP error code. Use the `path` field to indicate the specific destination or restricted item. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#address_undeliverable). |
| `address_unverifiable` | Error | The provided address couldn't be verified. Use the `path` field to indicate if it's the fulfillment or billing address. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#address_unverifiable). |
| `missing_fulfillment_info` | Error | Required fulfillment information is missing. Use the `path` field to specify the missing field. |
| `eligibility_invalid` | Error | User or order is not eligible for the action. This is a standard UCP error code. Use the `path` field for specifics. |
| `discount_code_invalid` | Warning | The discount code is invalid. Code not found or malformed. |
| `discount_code_expired` | Warning | The discount code has expired. |
| `discount_code_already_applied` | Warning | The discount code has already been applied. |
| `discount_code_combination_disallowed` | Warning | The discount code cannot be combined with other offers. |
| `discount_code_user_not_logged_in` | Warning | The user must be logged in to use the discount code. |
| `discount_code_user_ineligible` | Warning | The user is not eligible to use the discount code. |
| `missing_billing_info` | Error | Required billing information is missing. Use the `path` field to specify the missing billing address fields. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#missing_billing_info). |
| `identity_required` | Error | User identity is required for the requested operation, but was absent, invalid, expired, or unverifiable. For REST, use status code 401. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#identity_required). |
| `insufficient_scope` | Error | The user identity token is valid but lacks scope(s) required by the operation. For REST, use status code 403. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#insufficient_scope). |
| `payment_declined` | Error | The payment was declined by the card issuer or bank. Reasons can include insufficient funds, suspected fraud, or card issues. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#payment_declined). |
| `payment_failed` | Error | The payment failed due to a technical issue during processing---such as a network error, gateway timeout, or integration problem---which prevented the bank from reaching a decision. |
| `payment_ineligible` | Error | The selected payment method is not accepted. Suitable for cases when the user needs to try a different payment method. |
| `rejected_for_fraud` | Error | The order was rejected due to suspected fraud. See [example below](https://developers.google.com/merchant/ucp/guides/overview/error-codes#rejected_for_fraud). |
|   |   |   |

## Error code examples

This section provides JSON examples for the `messages` array for specific error
codes.

### `out_of_stock`

Single-item checkout:

    {
      "type": "error",
      "severity": "unrecoverable",
      "code": "out_of_stock",
      "content": "Unfortunately, the item 'Example Product 1' is out of stock."
    }

Multi-item checkout:

Use the `path` field to indicate the index of the specific item that is out of
stock.

    {
      "type": "error",
      "severity": "recoverable",
      "code": "out_of_stock",
      "path": "$.checkout.line_items[1]",
      "content": "The item 'Example Product 2' is out of stock. Remove it from your cart to continue."
    }

### `quantity_invalid_limit_exceeded`

    {
      "type": "error",
      "severity": "recoverable",
      "code": "quantity_invalid_limit_exceeded",
      "path": "$.checkout.line_items[0].quantity",
      "content": "The requested quantity for 'Example Product 2' exceeds the maximum allowed limit of 5."
    }

### `totals_changed`

    {
      "type": "warning",
      "code": "totals_changed",
      "path": "$.totals[2]",
      "content": "Shipping cost has changed."
    }

### `missing_buyer_info`

    {
      "type": "error",
      "severity": "recoverable",
      "code": "missing_buyer_info",
      "path": "$.buyer.first_name",
      "content": "Missing buyer first name."
    }

### `address_undeliverable`

Order-level restriction (e.g., zipcode not supported):

    {
      "type": "error",
      "severity": "recoverable",
      "code": "address_undeliverable",
      "content": "Delivery is not supported for the provided zipcode."
    }

Item-level restriction:

Use the `path` field to indicate a specific item that cannot be delivered to the
chosen destination (e.g., state-specific bans).

    {
      "type": "error",
      "severity": "recoverable",
      "code": "address_undeliverable",
      "path": "$.checkout.line_items[1]",
      "content": "The item 'Example Product 2' cannot be delivered to the selected address."
    }

### `address_unverifiable`

Billing address:

    {
      "type": "error",
      "severity": "recoverable",
      "code": "address_unverifiable",
      "path": "$.payment.instruments[0].billing_address",
      "content": "Invalid billing address. Update the address before trying again."
    }

Fulfillment address:

    {
      "type": "error",
      "severity": "recoverable",
      "code": "address_unverifiable",
      "path": "$.fulfillment.methods[0].destinations[0]",
      "content": "The fulfillment address couldn't be verified. Update the address and try again."
    }

### `missing_billing_info`

Use the `path` field to specify missing fields within the billing address.

    {
      "type": "error",
      "severity": "recoverable",
      "code": "missing_billing_info",
      "path": "$.payment.instruments[0].billing_address.street_address",
      "content": "Missing billing street address."
    }

### `identity_required`

In the REST API, this error should be returned with HTTP status code 401.

    {
      "type": "error",
      "severity": "requires_buyer_review",
      "code": "identity_required",
      "content": "User identity is required to access order history."
    }

### `insufficient_scope`

In the REST API, this error should be returned with HTTP status code 403.

    {
      "type": "error",
      "severity": "requires_buyer_review",
      "code": "insufficient_scope",
      "content": "This operation requires scopes: dev.ucp.shopping.order:read, dev.ucp.shopping.order:manage"
    }

### Payment errors

> [!NOTE]
> **Note:** In the REST API, you must return payment-related errors with an HTTP status code `200 OK` (not a 4xx or 5xx error). This ensures Google treats them as recoverable business errors, allowing the user to select a different payment method.

#### `payment_declined`

    {
      "type": "error",
      "severity": "recoverable",
      "code": "payment_declined",
      "path": "$.payment.instruments[0]",
      "content": "Payment was declined by the issuer. Try a different payment method or contact your bank."
    }

#### `rejected_for_fraud`

    {
      "type": "error",
      "severity": "recoverable",
      "code": "rejected_for_fraud",
      "path": "$.payment.instruments[0]",
      "content": "The order was rejected due to suspected fraud. Try a different payment method."
    }