Skip to content

Carry the enforced budget in sandbox timeout errors and steer agents to workflows - #1298

Merged
kentcdodds merged 5 commits into
mainfrom
cursor/execute-timeout-workflow-hint-6e77
Aug 10, 2026
Merged

kentcdodds merged 5 commits into
mainfrom
cursor/execute-timeout-workflow-hint-6e77

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Aug 7, 2026 •

Copy link
Copy Markdown
Member

Intent

Agents already get a proactive hint on the execute tool description that the sandbox has a ~90s hard timeout and that durable workflows.create is the right tool for longer work — but when a call actually timed out, the agent got no next step. The timeout message also had a source-ambiguity problem: the same string was emitted by ad hoc execute (90s), workflow-step sandboxes (270s), and package services (300s), so downstream consumers could not tell which budget was actually exceeded.

Summary

  • The executor now injects the enforced budget into the timeout message at every emission point (host deadline race, permit-queue abort, in-sandbox timer race): Execution timed out after 90s: Kody stopped observing the sandbox. …. The executor is the single component that knows the budget when the timeout fires, and the message string is the only part of the result that survives every boundary the error crosses (dynamic worker RPC, D1-persisted invocation responses, UserCodeError rethrows) — ExecuteResult.error is typed string by @cloudflare/codemode, so structured fields cannot ride along.
  • This composes with the abort-semantics explanation main recently added to the message (fix(runtime): harden ad hoc execute and package invoke #1309): executorSandboxTimeoutMessage is now built from an exported prefix (Execution timed out) plus the explanation, and the budget slots between them.
  • New execution_timed_out case in ExecutionErrorDetails (packages/worker/src/mcp/executor.ts), matched from the timeout message (prefix-tolerant for [execution_failed]-wrapped nested causes, anywhere in the error cause chain, and backward compatible with legacy budget-less and explanation-less forms). It carries the parsed timedOutAfterMs and a Next step: telling the agent not to retry the identical call and to submit genuinely long-running work as a durable workflow (workflows.create from kody:runtime, progress via workflow_run_list) or split the work — reporting the actual exceeded budget instead of assuming 90s.
  • The Sentry noise filter (isExecutorSandboxTimeoutSentryEvent in packages/worker/src/sentry-options.ts) accepts the budget and treats the explanation as optional while staying anchored, so wrapped rethrows (Error: Execution timed out…) still reach Sentry and legacy bare-form timeouts from older deployments stay muted.
  • The hint flows through both agent-facing surfaces automatically: the formatted text output (formatExecutionOutput) and structuredContent.errorDetails. docs/use/execute.md notes the budget annotation.

Testing

  • npm run validate passes locally after merging main (lint, typecheck, format, build, 588 unit test files / 2038 tests across Node and Workers projects, e2e).
  • packages/worker/src/mcp/executor.node.test.ts covers: real sandbox timeouts returning the budget-annotated message (host-deadline hang, permit-queue expiry, and abort-aware dispatcher paths), budget extraction for 90s and 270s messages, legacy budget-less and bare pre-explanation forms, a nested [execution_failed]-prefixed cause, and a non-matching mid-sentence mention.
  • packages/worker/src/sentry-options.node.test.ts covers: budget-annotated messages stay filtered (both s and ms spellings), the legacy bare form stays filtered, and Error: -prefixed rethrows still pass through.

System changes

System recap — extends one primitive (medium risk)

Mode: recap · Base: main @ d7f51175 · Head: 088bf1b8

Classification: extends — the MCP endpoint's execute error contract changes (timeout messages gain an injected budget; a new structured error kind is added); no primitives added, no other primitives touched.

Primitives touched

Primitive Group Impact
mcp-server surfaces extends — budget-annotated timeout message + new execution_timed_out kind in ExecutionErrorDetails

System map

Sandbox timeouts now carry their enforced budget in the message, and the execute error formatter turns that into a structured next step pointing at durable workflows.

Legend: green = composes (wiring only) · amber = extended by this PR · red = new primitive · gray = context (unchanged, included only when an edge crosses it).

flowchart LR
	executeSandbox["execute sandbox<br/>(dynamic worker)"]:::untouched
	mcpServer["mcp-server<br/>MCP endpoint (/mcp)"]:::extended
	sentry["Sentry noise filter<br/>sentry-options.ts"]:::extended
	workflows["workflows.create<br/>durable Cloudflare Workflows"]:::untouched
	executeSandbox -->|"'Execution timed out after 90s: …' (budget injected at emission)"| mcpServer
	mcpServer -->|"execution_timed_out details + Next step with parsed budget"| workflows
	mcpServer -->|"anchored budget-aware match keeps timeouts muted"| sentry
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Before / after

Agent-visible output when an execute call hits the sandbox deadline:

Before:

Error: Execution timed out: Kody stopped observing the sandbox. Nested work was asked to abort, but already-started remote work and side effects may still complete. Do not retry side-effecting work without an idempotencyKey; recover with run_get or replay the same idempotencyKey.

After:

Error: Execution timed out after 90s: Kody stopped observing the sandbox. Nested work was asked to abort, but already-started remote work and side effects may still complete. Do not retry side-effecting work without an idempotencyKey; recover with run_get or replay the same idempotencyKey.

Next step: The sandbox enforces a hard execution time budget and this run used its full 90s, so retrying the identical call will time out again. For genuinely long-running work (batch sweeps, migrations, polling loops), have one short execute call submit a durable workflow — `import { workflows } from 'kody:runtime'` then `workflows.create({ code, params })` — and inspect progress with `workflow_run_list`. Otherwise split the work into smaller calls that each finish well within the budget.

A workflow-step sandbox cut reports after 270s; legacy budget-less messages (older stored responses) still classify with timedOutAfterMs: null and the generic ~90s wording.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • Bug Fixes

    • Timeout errors now show the enforced execution duration.
    • Timeout handling provides clearer structured details and guidance for resolving the issue.
    • Queued evaluations retain the original timeout reason when canceled.
    • Timeout reporting and filtering now work consistently across supported timeout formats.
  • Documentation

    • Added guidance explaining timeout budgets and recommended next steps.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Aug 7, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: be0ddc28-bf6e-4a4d-9bcb-edf4f832d5b5

📥 Commits

Reviewing files that changed from the base of the PR and between d7f5117 and 088bf1b.

📒 Files selected for processing (5)
  • docs/use/execute.md
  • packages/worker/src/mcp/executor.node.test.ts
  • packages/worker/src/mcp/executor.ts
  • packages/worker/src/sentry-options.node.test.ts
  • packages/worker/src/sentry-options.ts

📝 Walkthrough

Walkthrough

Sandbox timeout errors now include enforced budgets. Executor parsing returns structured timeout details and workflow guidance. Sentry filtering recognizes annotated and legacy timeout messages while excluding wrapped or unrelated errors.

Changes

Executor timeout handling

Layer / File(s) Summary
Timeout message contract and Sentry filtering
packages/worker/src/sentry-options.ts, packages/worker/src/sentry-options.node.test.ts
Shared timeout constants and matching support annotated durations, legacy messages, and exact Sentry filtering.
Executor timeout propagation
packages/worker/src/mcp/executor.ts
Host, sandbox, and queued evaluation timeouts use budget-bearing messages and preserve timeout reasons.
Structured timeout diagnostics and validation
packages/worker/src/mcp/executor.ts, packages/worker/src/mcp/executor.node.test.ts, docs/use/execute.md
Timeout parsing returns execution_timed_out details with parsed budgets, workflow guidance, and fix_code action. Tests and documentation cover the new formats.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: kody-bot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: adding enforced budgets to sandbox timeout errors and directing agents to workflows.
Description check ✅ Passed The description includes complete Intent, Summary, Testing, and System changes sections with relevant implementation details, risks, and test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/execute-timeout-workflow-hint-6e77

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@cursor cursor Bot changed the title Add durable-workflow next step to execute timeout errors Carry the enforced budget in sandbox timeout errors and steer agents to workflows Aug 7, 2026
@kody-bot
kody-bot marked this pull request as ready for review August 8, 2026 05:47
@github-actions

github-actions Bot commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-1298.kody-a99.workers.dev

Worker: kody-pr-1298
D1: kody-pr-1298-db
KV: kody-pr-1298-oauth-kv

Mocks:

cursoragent and others added 3 commits August 10, 2026 05:14
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
…t-workflow-hint-6e77

# Conflicts:
#	packages/worker/src/mcp/executor.ts

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds
kentcdodds merged commit 0f67367 into main Aug 10, 2026
10 checks passed
@kentcdodds
kentcdodds deleted the cursor/execute-timeout-workflow-hint-6e77 branch August 10, 2026 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants