Schedule-triggered sessions can't park: "Cannot park: no continuation token available"
Summary
In eve 0.13.2 (also present on main), sessions started by a cron schedule fail with Error: Cannot park: no continuation token available as soon as the turn loop emits a park action. The dispatcher calls runtime.run({...}) without a continuationToken, the workflow context seeds eve.continuationToken as "", and the driver's park guard rejects the empty token. The run handle has a usable token (run.runId), but it's never written back into the session state, so it can't satisfy the guard.
Reproduction
Any schedule whose first turn needs to park (e.g. an authorization.required gate, or a handler-form schedule waiting for a channel reply) hits this.
- Define a markdown schedule:
import { defineSchedule } from "eve/schedules";
export default defineSchedule({
cron: "0 9 * * *",
markdown: "Audit the queue and file a summary for any blocked item.",
});
- Trigger it out-of-band in dev:
curl -X POST http://localhost:3000/eve/v1/dev/schedules/your-schedule
- Stream the returned session:
curl -N http://localhost:3000/eve/v1/session/<sessionId>/stream
- The session terminates with
session.failed whose error is Cannot park: no continuation token available.
Expected vs actual
- Expected (per
docs/schedules.mdx): A handler-form session "runs on the same durable runtime engine as any other session, so it can park (durably suspend), for instance when the channel handoff is waiting for a Slack reply." Schedule runs that need to park should durably suspend.
- Actual: The first
park action fails with the error above; the session terminates instead of suspending.
Root cause (eve 0.13.2, tag eve@0.13.2)
Three pieces conspire:
schedule.ts:116-122 — ScheduleDispatcher.runMarkdown calls runtime.run({ adapter, auth, input, mode: "task" }) without a continuationToken.
runtime-context.ts:38 — buildRunContext does ctx.set(ContinuationTokenKey, run.continuationToken ?? ""), so the serialized workflow context carries eve.continuationToken = "".
workflow-entry.ts:253-262 — the park guard throws when action.sessionState.continuationToken is falsy.
The run.runId fallback exists only on the returned handle (workflow-runtime.ts:113, continuationToken: input.continuationToken ?? run.runId) and is never reflected back into the session state the driver parks on.
The park action is reachable in task mode via canPark being satisfied by hasPendingAuthorization (turn-workflow.ts:77-81), which is how this surfaces even in fire-and-forget task-mode schedules.
On main / 0.16.x the same logic is at workflow-entry.ts:197-204 (with runtime-context.ts:39).
Stack trace
Error: Cannot park: no continuation token available. The channel must post the
first message during the initial turn (anchoring the session) or `send()` must
be called with an explicit continuationToken.
at runDriverLoop (packages/eve/src/execution/workflow-entry.ts:257)
at workflowEntry (packages/eve/src/execution/workflow-entry.ts:76)
The guard that fires is the if (!action.sessionState.continuationToken) check on the preceding line.
Workaround (until fixed)
Until this is fixed, two options that don't require parking:
- Drive the entire flow inside a single
Workflow tool JavaScript block so subagents complete (done) without crossing a park boundary.
- For handler-form schedules that genuinely need a channel reply, manually seed a non-empty
continuationToken before the first park.
Both are band-aids; the fix is to either:
- Have
ScheduleDispatcher.runMarkdown seed a real token (run.runId is already computed for the handle), OR
- Have the park guard seed
sessionState.continuationToken from the handle's token before checking.
Environment
- eve: 0.13.2 (also present on
main)
- Node: 24 (per repo
.nvmrc)
- Platform: any (framework code, not platform-specific)
Schedule-triggered sessions can't park: "Cannot park: no continuation token available"
Summary
In eve 0.13.2 (also present on
main), sessions started by a cron schedule fail withError: Cannot park: no continuation token availableas soon as the turn loop emits aparkaction. The dispatcher callsruntime.run({...})without acontinuationToken, the workflow context seedseve.continuationTokenas"", and the driver's park guard rejects the empty token. The run handle has a usable token (run.runId), but it's never written back into the session state, so it can't satisfy the guard.Reproduction
Any schedule whose first turn needs to park (e.g. an
authorization.requiredgate, or a handler-form schedule waiting for a channel reply) hits this.session.failedwhose error isCannot park: no continuation token available.Expected vs actual
docs/schedules.mdx): A handler-form session "runs on the same durable runtime engine as any other session, so it can park (durably suspend), for instance when the channel handoff is waiting for a Slack reply." Schedule runs that need to park should durably suspend.parkaction fails with the error above; the session terminates instead of suspending.Root cause (eve 0.13.2, tag
eve@0.13.2)Three pieces conspire:
schedule.ts:116-122—ScheduleDispatcher.runMarkdowncallsruntime.run({ adapter, auth, input, mode: "task" })without acontinuationToken.runtime-context.ts:38—buildRunContextdoesctx.set(ContinuationTokenKey, run.continuationToken ?? ""), so the serialized workflow context carrieseve.continuationToken = "".workflow-entry.ts:253-262— the park guard throws whenaction.sessionState.continuationTokenis falsy.The
run.runIdfallback exists only on the returned handle (workflow-runtime.ts:113,continuationToken: input.continuationToken ?? run.runId) and is never reflected back into the session state the driver parks on.The
parkaction is reachable in task mode viacanParkbeing satisfied byhasPendingAuthorization(turn-workflow.ts:77-81), which is how this surfaces even in fire-and-forget task-mode schedules.On
main/ 0.16.x the same logic is atworkflow-entry.ts:197-204(withruntime-context.ts:39).Stack trace
The guard that fires is the
if (!action.sessionState.continuationToken)check on the preceding line.Workaround (until fixed)
Until this is fixed, two options that don't require parking:
Workflowtool JavaScript block so subagents complete (done) without crossing a park boundary.continuationTokenbefore the first park.Both are band-aids; the fix is to either:
ScheduleDispatcher.runMarkdownseed a real token (run.runIdis already computed for the handle), ORsessionState.continuationTokenfrom the handle's token before checking.Environment
main).nvmrc)