Imported from report.md (HIGH_BUG).
- File:
apps/api/src/lib/workflows/trial-end.ts
- Lines: 291, 335
- Slug: other-race-condition
- Confidence: medium
The no-card/data and no-provider fallback paths update the subscription to expired with WHERE id = ? only. Earlier paths correctly guard on status = 'trialing'. If a provider webhook or another workflow path activates the trial after the initial status check but before these fallback updates, these branches can overwrite the active subscription as expired.
Recommendation: Add AND status = 'trialing' to all expiry/cancel fallback updates and check the affected row count before invalidating cache or reporting success.
Imported from
report.md(HIGH_BUG).apps/api/src/lib/workflows/trial-end.tsThe no-card/data and no-provider fallback paths update the subscription to expired with WHERE id = ? only. Earlier paths correctly guard on status = 'trialing'. If a provider webhook or another workflow path activates the trial after the initial status check but before these fallback updates, these branches can overwrite the active subscription as expired.
Recommendation: Add AND status = 'trialing' to all expiry/cancel fallback updates and check the affected row count before invalidating cache or reporting success.