You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BountiesService.expireOverdue() overwrites concurrently-advanced bounties to EXPIRED — read-then-save with no status re-check and no assertTransition #460
BountiesService.expireOverdue(), run hourly by BountyExpiryScheduler, loads every overdue OPEN, FUNDED or CLAIMED bounty and then saves them one at a time:
constoverdue=awaitthis.bountyRepo.createQueryBuilder('bounty').where('bounty.deadline IS NOT NULL AND bounty.deadline < :now',{now: newDate()}).andWhere('bounty.status IN (:...statuses)',{statuses: [OPEN,FUNDED,CLAIMED]}).getMany();for(constbountyofoverdue){bounty.status=BountyStatus.EXPIRED;awaitthis.bountyRepo.save(bounty);}
The status filter only applies at read time. Between the SELECT and each save(), and across a loop of per-row awaits that can take a while on a large backlog, a webhook can move the same bounty forward: CLAIMED → IN_REVIEW when a PR opens (#168), or on to MERGED and PAID. The save() then issues UPDATE ... SET status='expired' WHERE id=... from the stale in-memory copy and clobbers the newer status.
The loop also skips assertTransition(), unlike every other status change in BountiesService, so it doesn't consult the state machine (IN_REVIEW → EXPIRED isn't a valid transition).
A bounty that has just been merged and paid can be flipped to EXPIRED. Since EXPIRED → REFUNDED is allowed, the sponsor can then also refund a bounty that was already paid out.
Suggested fix
Replace the loop with one conditional update, so the status check and the write are atomic:
constresult=awaitthis.bountyRepo.createQueryBuilder().update(Bounty).set({status: BountyStatus.EXPIRED}).where('deadline IS NOT NULL AND deadline < :now',{ now }).andWhere('status IN (:...statuses)',{statuses: [OPEN,FUNDED,CLAIMED]}).execute();returnresult.affected??0;
Or, per row: update({ id, status: In([...]) }, { status: EXPIRED }) and count affected. Add a test where the bounty's status changes between the read and the write, and it isn't expired.
I have submitted a clean, atomic fix resolving this race condition in PR #468. Replaced the iterative save loop with a single atomic conditional UPDATE matching eligible statuses and verified with 14/14 passing unit tests.
Congratulations, @Ultra-Tech-code! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on September 30, 2026.
🧑💻 @Ultra-Tech-code: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.
Warning
When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.
🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.
Congratulations, @Youngthreader! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on October 22, 2026.
🧑💻 @Youngthreader: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.
Warning
When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.
🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.
Activity
Proxima84-code commentedon Sep 27, 2026
I have submitted a clean, atomic fix resolving this race condition in PR #468. Replaced the iterative save loop with a single atomic conditional UPDATE matching eligible statuses and verified with 14/14 passing unit tests.
drips-wave commentedon Sep 29, 2026
Congratulations, @Ultra-Tech-code! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on September 30, 2026.
🧑💻 @Ultra-Tech-code: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.
Warning
When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.
🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.
🌊 Happy Wave 🌊
fix(bounties): resolve merge conflicts, decorator imports, and test d…
fix(bounties): replace read-then-save in expireOverdue with atomic st…
fix(bounties): replace read-then-save in expireOverdue with atomic st…
Youngthreader commentedon Oct 20, 2026
@Youngthreader has applied to work on this issue as part of the Stellar Wave Program's 10th wave.
ℹ️ Repo Maintainers: To accept this application, review their application or assign @Youngthreader to this issue.
drips-wave commentedon Oct 21, 2026
Congratulations, @Youngthreader! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on October 22, 2026.
🧑💻 @Youngthreader: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.
Warning
When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.
🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.
🌊 Happy Wave 🌊
fix: BountiesService.expireOverdue() overwrites concurrently-adva (Me…
fix: BountiesService.expireOverdue() overwrites concurrently-adva (Me…