PolarSelfClient (server/polar/integrations/polar/client.py) calls api.polar.sh (e.g. list_recurring_products -> GET /v1/products/) with no explicit httpx.Timeout and no retry/backoff. Any httpx.RequestError (e.g. ReadError, connection reset mid-read) is wrapped as PolarNetworkError -> PolarSelfClientOperationalError, which callers like organization.endpoints.list_plans do not catch, so it surfaces as a bare 500.
This isn't a one-off: Logfire shows the same ReadError -> PolarNetworkError chain hitting api.polar.sh at a baseline of 1-2/hr across both the api and worker services (also hit worker's get_order webhook processing the same day), plus a larger spike of 111 errors in one hour on 2026-07-20. Reference: Sentry SERVER-4WB.
Suggested fix
Related
Sent by @maximevast from Stilla investigation.
PolarSelfClient(server/polar/integrations/polar/client.py) callsapi.polar.sh(e.g.list_recurring_products->GET /v1/products/) with no explicithttpx.Timeoutand no retry/backoff. Anyhttpx.RequestError(e.g.ReadError, connection reset mid-read) is wrapped asPolarNetworkError->PolarSelfClientOperationalError, which callers likeorganization.endpoints.list_plansdo not catch, so it surfaces as a bare 500.This isn't a one-off: Logfire shows the same
ReadError->PolarNetworkErrorchain hittingapi.polar.shat a baseline of 1-2/hr across both theapiandworkerservices (also hitworker'sget_orderwebhook processing the same day), plus a larger spike of 111 errors in one hour on 2026-07-20. Reference: Sentry SERVER-4WB.Suggested fix
httpx.Timeoutand retry/backoff toPolarSelfClient's underlying httpx transport, following the pattern already used for the Tinybird client (Tinybird client: distinguish operational errors (network/server) from legitimate API errors #10652).list_plans()/list_recurring_products()calls inorganization/endpoints.pyto degrade gracefully instead of propagating a bare 500.Related
PolarSelfClientOperationalErrorclassification (403 case)Sent by @maximevast from Stilla investigation.