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
Agent.destroy() leaves the Durable Object behind in production: deleted deadman alarm fires after abort #2605
Agent.destroy() does not remove the Durable Object in production. About 30s after destroy() runs from a scheduled callback, the object wakes up, and the Agent constructor recreates the SDK's tables. Each destroyed agent is left behind with about 15 empty tables and never goes away.
This looks like the same symptom as #616, which was closed after #653.
Cause
destroy() ends with deleteAlarm() (through lifecycle.disableAlarms()), then deleteAll(), then a deferred ctx.abort(reason, { retryAlarm: false }). In production, an alarm deleted just before ctx.abort() still fires. The alarm here is the 30s deadman alarm (DEADMAN_ALARM_DELAY_MS) that _driveDueJobs sets before running due jobs.
We reproduced it without the SDK, using only those platform calls. With the abort, 5 of 6 objects woke again. Without it, 0 of 4 did. Runtime report: cloudflare/workerd#7788
Reproduction (SDK)
agents@0.27.0 and @cloudflare/ai-chat@0.12.1. 0.28.1 has the same destroy().
compatibility_date is 2026-03-02, with SQLite-backed Durable Objects.
An AIChatAgent subclass schedules a callback (this.schedule(seconds, 'expire')). The callback calls await this.destroy().
Point
Tables
getAlarm()
Right after destroy()
0
null
~30s later, constructor runs (12 of 12 objects, within 56ms of the deadman time)
0, then 15 after the constructor's migrations
null
Woken manually 5 to 26 minutes later
15
null
Calling deleteAlarm() and storage.sync() before destroy() did not help, and neither did _cf_scheduleDestroy(). Local wrangler dev does not reproduce it.
Request
Please make destroy() remove the object even with this runtime behavior. Options include tearing down without ctx.abort(), or doing so until the runtime issue is fixed. Wiping storage and returning from alarm() without aborting left 0 of 4 objects behind in our test.
Activity