Skip to content

πŸ› Bug Report β€” Runtime APIs: Facet ctx.storage.setAlarm() silently breaks SQLite-backed DO actor in local devΒ #6810

Description

@firtoz

In wrangler dev, calling ctx.storage.setAlarm() from inside a Durable Object facet of a SQLite-backed DO appears to succeed, then asynchronously breaks the whole actor with:

Error: alarms are not yet implemented for SQLite-backed Durable Objects

The error does not throw from the setAlarm() call. It surfaces as the rejection of an unrelated in-flight RPC into the facet, with no facet-side stack frames.

Minimal repro: https://github.com/firtoz/facet-alarm-repro

Repro

git clone https://github.com/firtoz/facet-alarm-repro
cd facet-alarm-repro
npm install
npx wrangler dev

curl 'http://127.0.0.1:8799/repro'
curl 'http://127.0.0.1:8799/repro?facetAlarm=off'

Expected:

  • /repro should either complete, or setAlarm() inside the facet should throw synchronously with a clear "facet alarms are unsupported" error.
  • /repro?facetAlarm=off should complete.

Actual:

  • /repro returns ok: false; the host -> facet RPC rejects with alarms are not yet implemented for SQLite-backed Durable Objects.
  • /repro?facetAlarm=off completes normally.

Important detail

The facet's setAlarm() call logs success before the actor breaks:

{"tag":"leaf:hold:start","ms":4000,"setAlarm":true}
{"tag":"leaf:setAlarm:ok"}

So userland cannot catch this at the alarm call site.

Environment

  • Reproduced on wrangler 4.85.0 through 4.100.0.
  • compatibility_date: 2026-04-24
  • SQLite-backed DO via new_sqlite_classes
  • Facet spawned with ctx.facets.get(name, () => ({ class: ctx.exports.Leaf }))
  • Linux x64

Likely source

From workerd source:

  • src/workerd/server/server.c++: facet actors (parent != kj::none) get ActorSqlite::Hooks::getDefaultHooks() with a TODO: Support alarms in facets, somehow.
  • src/workerd/io/actor-sqlite.c++: default Hooks::scheduleRun() throws alarms are not yet implemented for SQLite-backed Durable Objects.

It looks like the output-gate commit path calls scheduleRun() after the JS setAlarm() call has already resolved, breaking the actor asynchronously.

Why this matters

Frameworks like agents / Think use alarms for keep-alive and scheduling. If such framework code runs inside a facet, the actor can be broken by a successful-looking setAlarm() call, and the error appears elsewhere as an unrelated RPC failure.

Suggested fix

Either:

  1. Support facet alarms in local workerd; or
  2. Make setAlarm() on facet storage throw synchronously at the call site in local dev, with an error that explicitly says alarms are unsupported in facets.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions