Skip to content

fix(rest/python): return not found for expired carts - #275

Open
arjun2075 wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
arjun2075:fix/python-expired-cart
Open

arjun2075 wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
arjun2075:fix/python-expired-cart

Conversation

@arjun2075

Copy link
Copy Markdown
Contributor

Problem

A cart past its expires_at was still served by GET /carts/{id} and could still be converted into a checkout with POST /checkout-sessions {"cart_id": ...}. Create Cart sets expires_at seven days out, but nothing ever read it.

Root cause

CartService.get_cart and the cart load in CheckoutService.create_checkout only checked that the stored cart exists.

Spec

cart.md, Get Cart: "Returns not_found if the cart does not exist, has expired, or was canceled." The same document says platforms SHOULD handle not_found when a cart expires or is canceled. Checked against tag v2026-04-08.

Fix

A small is_cart_expired helper treats a cart as expired from the instant expires_at is reached (expires_at <= now); a cart with no expires_at never expires. get_cart and the cart-to-checkout conversion raise the existing ResourceNotFoundError (404, RESOURCE_NOT_FOUND in the UCP error envelope), the same answer a missing cart already gets. The Z suffix is normalised so the parse also works on Python 3.10, which the package still supports.

Regression coverage

In cart_test.py:

  • an expired cart answers 404 RESOURCE_NOT_FOUND on GET /carts/{id}
  • an expired cart cannot be converted: POST /checkout-sessions with its cart_id answers 404 and no checkout is created for it
  • a cart with a future expiry is still served and still converts
  • the exact boundary: expired one microsecond before, at, but not one microsecond after expires_at; a cart with no expiry never expires

The three expired-cart tests fail on main (200 and 201 instead of 404).

Validation

  • rest/python/server: uv run pytest, 363 passed
  • ruff check and ruff format clean

Out of scope

Update and cancel on an expired cart, and returning an already-existing incomplete checkout for a cart, are unchanged.

A cart past its expires_at was still served by GET /carts/{id} and could still be converted into a checkout. cart.md (Get Cart) says an expired cart is not_found, but nothing read expires_at. Add is_cart_expired (expired from the instant expires_at is reached) and use it in get_cart and the cart-to-checkout conversion, which now answer with the existing 404 RESOURCE_NOT_FOUND envelope. Add tests for both paths, an unexpired control, and the exact expiry boundary.
@google-cla

google-cla Bot commented Nov 4, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status:needs-triage Signal that the PR is ready for human triage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants