# Handle errors in Cart management When working with Carts, several types of errors can occur. Understanding and handling errors correctly ensures a smoother shopping experience for your customers. Typical error scenarios include: - **Version conflicts:** another process updated the Cart between your read and update actions. - **Invalid data:** incorrect SKU, currency, or other required fields missing. - **Cart not found:** attempting to operate on a Cart that no longer exists or was deleted. - **Authorization errors:** using an incorrect `anonymousId`, `customerId`, or missing permissions. - **Price mismatch:** price selection failed because no matching price was found for country, currency, and Channel. - **CartState issues:** trying to update a `Merged`, `Frozen`, or `Ordered` Cart. Error responses have the following structure across the different commercetools APIs: ```json { "statusCode": 401, "message": "Example error message.", "errors": [ { "code": "invalid_token", "message": "Example error message." }, ] } ``` - **statusCode:** HTTP status code corresponding to the error. - **message:** first error message in the `errors` array. - **errors:** errors returned for a request. A single error response can contain multiple errors if the errors are related to the same HTTP status code such as `400`. For the full HTTP status and error-code catalog, see the [API error documentation](/api/errors.md). In Cart management, the most useful distinction is how your application should recover from each type of error: | Status code | Meaning | Suggested handling | | :--- | :--- | :--- | | `400` Bad Request | Indicates an issue with the request itself, such as invalid JSON or missing required fields. | Consult the docs and validate input before sending. | | `401` Unauthorized | Occurs when your API client lacks the necessary authentication credentials or scopes. | Revise scopes of the API key, ensure you have a valid access token and the required scopes for the operation. | | `403` Forbidden | Your API client has valid credentials but lacks permission to perform the requested action. | Verify your API client’s roles and permissions. | | `404` Not Found | The requested Cart or resource does not exist. | Make sure you are using the right Cart ID or key. | | `5xx` Server Errors | Indicate an issue on the commercetools side. | Retry your request after a short delay. If the issue persists, contact commercetools support. | ## Best practices for error handling commercetools uses standard HTTP status codes to indicate errors. Your error-handling logic should: - Catch errors in API requests. - Examine the `statusCode` and `errors` array in the API response. - Implement retry mechanisms for recoverable errors like server errors or rate limiting. - Log all errors for debugging and monitoring. - Handle errors gracefully. Provide informative error messages to the customer and avoid exposing technical details. ### Handle version conflicts Version conflicts occur when you try to update a Cart that has already been modified. Here’s how Zen Electron handles version conflict when executing a [CartUpdateAction](/search.md?urn=ctp:api:type:CartUpdateAction) such as adding or removing an item from the Cart. ```typescript import { ErrorResponse } from "@commercetools/platform-sdk"; // Code to create an array of CartUpdateAction for example addLineItemAction, removeLineItemAction try { const response = await apiRoot .inStoreKeyWithStoreKeyValue({ storeKey }) .carts() .withId({ ID: cartId }) .post({ body: { version, actions } }) .execute(); } catch (error) { const errorResponse = error as ErrorResponse; if (errorResponse.statusCode === 409) { // Version conflict. Handle error for example Handle by using the version number in the error body here or do this in the middleware layer. } else { // Handle other errors } } ``` ### Handle Not Found and Authorization errors When fetching a Cart or creating one, it’s possible the requested Cart might not exist or belong to that Store, or the user does not have access. ```typescript import { ErrorResponse } from "@commercetools/platform-sdk"; // Existing code try { const response = await apiRoot .inStoreKeyWithStoreKeyValue({ storeKey }) .carts() .withId({ ID: cartId }) .get() .execute(); } catch (error) { const errorResponse = error as ErrorResponse; if (errorResponse.statusCode === 404) { // Cart not found. Handle error for example return undefined or rethrow the error and handle it on a higher level in the call stack. } else if (errorResponse.statusCode === 403) { // Access denied to Cart, API Client doesn't have permission to access the Cart } else () { // Handle other errors } } ``` ### Security: validate Cart ownership A critical security measure is to ensure you only return a Cart to its rightful owner. Fetching a Cart by its `id` alone does not validate ownership. A malicious actor could potentially guess Cart IDs to view another user's Cart contents. After successfully fetching a Cart, your backend application must verify that its `customerId` (for logged-in users) or `anonymousId` (for guest users) matches the identifier of the user making the request. **Recommended verification flow**: 1. The frontend makes a request to your BFF API to get the Cart. 2. Your API authenticates the user and gets their `userId` or `anonymousId` from their session/token. 3. Your API fetches the Cart from commercetools using the `cartId`. 4. Crucially, your API compares the `cart.body.customerId` or `cart.body.anonymousId` with the user's ID from the session. 5. If they match, return the Cart. 6. If they do not match, treat it as a `404 Not Found` to avoid leaking information that the Cart exists. Log this as a potential security event. ### API design: communicating state changes and partial success When a user modifies their Cart, the frontend may need to provide specific feedback, such as "Item X was added to your Cart" or "The quantity for Item Y was updated." Simply receiving the updated Cart object from the API is not enough, as the frontend doesn't automatically know what changed between the update and the last version of the Cart. The BFF's primary responsibility is to bridge this gap. It must inspect the client's request, observe the result from the commercetools API, and return a structured response that explicitly describes the outcome of each requested change. This pattern involves reconciling the initial intent (the `actions` array) with the final outcome (the updated Cart and the `errors` array from the API response). **Recommended reconciliation pattern:** 1. **Receive and retain**: the BFF receives a request from the client containing the list of `actions` to perform. The BFF must keep this list in memory for the next step. 2. **Execute**: the BFF sends the `actions` to the commercetools API. 3. **Analyze the response**: the BFF must inspect both the updated `cart` object and the `errors` array in the response body. 4. **Reconcile and build response**: the BFF iterates through the original `actions` it received from the client and any actions it added. For each action, it determines if it succeeded or failed. 5. **Construct a rich response**: the BFF sends a response to the client that includes: - The final, updated `cart` object with the necessary field. - A structured `changes` or `messages` object that clearly lists the successful and failed operations, providing enough detail for the UI to display meaningful notifications. ## Related pages - [Area overview page with navigation](/learning-implement-carts-and-shopping-lists.md) - [Previous page: Manage Cart sessions and merges](/learning-implement-carts-and-shopping-lists/implement-carts/manage-cart-sessions-and-merges.md) - [Next page: Learning check](/learning-implement-carts-and-shopping-lists/implement-carts/learning-check.md) - [Search documentation and API specs](/search.md)