Skip to content

Commit 1ca0826

Browse files
Mark Hendersonfwang
authored andcommitted
fix: reorder operations in clearSession and reply to prevent race condition
1 parent 700188f commit 1ca0826

1 file changed

Lines changed: 20 additions & 10 deletions

File tree

  • packages/opencode/src/permission

packages/opencode/src/permission/next.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,15 @@ export namespace PermissionNext {
5050
const s = await state()
5151
for (const [id, pending] of Object.entries(s.pending)) {
5252
if (pending.info.sessionID === sessionID) {
53-
delete s.pending[id]
53+
// Order: reject promise, publish event, then delete from map
54+
// This ensures handlers can safely access pending state
55+
pending.reject(new RejectedError())
5456
Bus.publish(Event.Replied, {
5557
sessionID: pending.info.sessionID,
5658
requestID: pending.info.id,
5759
reply: "reject",
5860
})
59-
pending.reject(new RejectedError())
61+
delete s.pending[id]
6062
}
6163
}
6264
}
@@ -204,29 +206,37 @@ export namespace PermissionNext {
204206
const s = await state()
205207
const existing = s.pending[input.requestID]
206208
if (!existing) return
207-
delete s.pending[input.requestID]
208-
Bus.publish(Event.Replied, {
209-
sessionID: existing.info.sessionID,
210-
requestID: existing.info.id,
211-
reply: input.reply,
212-
})
209+
// Order: reject/resolve promise, publish event, then delete from map
210+
// This ensures handlers can safely access pending state
213211
if (input.reply === "reject") {
214212
existing.reject(input.message ? new CorrectedError(input.message) : new RejectedError())
213+
Bus.publish(Event.Replied, {
214+
sessionID: existing.info.sessionID,
215+
requestID: existing.info.id,
216+
reply: input.reply,
217+
})
218+
delete s.pending[input.requestID]
215219
// Reject all other pending permissions for this session
216220
const sessionID = existing.info.sessionID
217221
for (const [id, pending] of Object.entries(s.pending)) {
218222
if (pending.info.sessionID === sessionID) {
219-
delete s.pending[id]
223+
pending.reject(new RejectedError())
220224
Bus.publish(Event.Replied, {
221225
sessionID: pending.info.sessionID,
222226
requestID: pending.info.id,
223227
reply: "reject",
224228
})
225-
pending.reject(new RejectedError())
229+
delete s.pending[id]
226230
}
227231
}
228232
return
229233
}
234+
delete s.pending[input.requestID]
235+
Bus.publish(Event.Replied, {
236+
sessionID: existing.info.sessionID,
237+
requestID: existing.info.id,
238+
reply: input.reply,
239+
})
230240
if (input.reply === "once") {
231241
existing.resolve()
232242
return

0 commit comments

Comments
 (0)