fix(customer-session): return 409 on ambiguous external customer ID across orgs - #13913
Open
detail-app[bot] wants to merge 2 commits into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
OpenAPI ChangesOperations
|
joebon
approved these changes
Aug 20, 2026
Contributor
|
Preview Environment |
joebon
approved these changes
Aug 20, 2026
frankie567
requested changes
Aug 20, 2026
| from polar.exceptions import PolarError | ||
|
|
||
|
|
||
| class AmbiguousExternalCustomerID(PolarError): |
Member
There was a problem hiding this comment.
@detail-dev Why putting the exception in a dedicated module? This is not our pattern. It should Iive server/polar/customer_session/service.py
Contributor
Author
There was a problem hiding this comment.
Addressed in fbbd153. Removed and defined locally in each module's ( and ).
frankie567
approved these changes
Aug 20, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detail bug report: View on Detail
Summary
POST /v1/customer-sessions/returned HTTP 500 (triggering Sentry alerts) when a User token spans multiple organizations that each have a customer with the sameexternal_id. It now returns HTTP 409 with a disambiguation message, matching the existingMemberServicebehavior.Bug
CustomerSessionService._get_customer()callsCustomerRepository.get_readable_by_external_id(), which usesscalar_one_or_none(). The schema allows the sameexternal_idacross organizations (UniqueConstraint("organization_id", "external_id")), and the endpoint accepts User tokens that can span multiple orgs. When two accessible orgs each have a customer with the sameexternal_id, SQLAlchemy raisesMultipleResultsFound— which propagated uncaught as HTTP 500, violating theAGENTS.mdconvention that expected business conflicts return a proper status code (not 500/Sentry).This was inconsistent with three other callers of the same repository method (
MemberService.create,MemberService.get_by_external_id,backoffice/orders_import.py), all of which catch the exception and return a 409.Introduced in commit
6115ebe7(PR #11146), which migrated customer_session to useget_readable_by_external_id()without adding the exception handler.Fix
AmbiguousExternalCustomerID(aPolarErrorwithstatus_code=409) frompolar/member/service.pyto a new shared modulepolar/customer/exceptions.py, since the error is about customers and is now consumed by both services.try/except MultipleResultsFoundaround theget_readable_by_external_id()call inCustomerSessionService._get_customer(), raisingAmbiguousExternalCustomerID— mirroring the exact pattern already used inMemberService.MemberServiceandMemberEndpointsto import from the shared location (no behavior change).409: AmbiguousExternalCustomerin the endpoint'sresponses=so the OpenAPI schema and generated SDK expose the conflict shape.clients/packages/client/src/v1.ts.Testing
test_external_customer_id_ambiguous_across_organizationstotests/customer_session/test_endpoints.py— creates two customers with the sameexternal_idacross two orgs the user belongs to, POSTs to/v1/customer-sessions/, and asserts 409.customer_sessionendpoint and service tests pass (33 tests) — confirms no regression in the happy path, org-scoped tokens,customer_idlookups, member-model-enabled flows, and not-found cases.membertests pass (140 tests), including the existingtest_external_ambiguous_across_organizationstests — confirms the moved exception class still produces 409 in the member module.customertests pass (178 tests) — confirms no import cycles from the newexceptions.py.checkoutservice tests pass (359 tests) — confirms no import cycle viapolar.member.service.I attempted end-to-end verification against a standalone uvicorn server with a real Personal Access Token, but the server's auth middleware could not resolve the PAT outside the pytest test client (returned
RuntimeError: AuthSubject is not present in the request state). This is an auth-infrastructure issue unrelated to the fix — the integration tests exercise the identical code path through the full ASGI stack (realPolarErrorhandler, endpoint, service, and DB).Automatic Fixes PRs can be configured here.