Skip to content

bug(retained): destroy the environment when detached dispatch fails #799

Description

@drewstone

Reproduction

The retained start path creates an environment before detached dispatch.

If provider.create succeeds and environment.dispatch rejects, startRetainedRun propagates the dispatch error and does not call environment.destroy.

A focused injected-provider reproduction measured created=1, dispatched=1, destroyed=0 against @tangle-network/agent-runtime 0.132.6.

The missing cleanup is in the post-create path of startRetainedRun in src/runtime/retained-run-start.ts.

Impact

Each failed dispatch can leave one paid cloud environment alive until its external lifetime expires.

Braid hit the adjacent public path on 2026-08-12. Sandbox creation succeeded, dispatch returned HTTP 404, and only the external proof cleanup prevented a leak.

Required behavior

Wrap detached dispatch and exact-reference validation in cleanup.

Call environment.destroy when any post-create step fails before a RetainedRunHandle is returned.

Preserve the original error and include cleanup failure in an AggregateError.

Do not destroy an environment after a valid handle has crossed the admission boundary.

Completion proof

  1. A dispatch rejection destroys exactly one created environment.
  2. An invalid control reference destroys exactly one created environment.
  3. A destroy failure preserves both errors.
  4. A successful retained start does not destroy the environment.
  5. The real Tangle Sandbox failure path leaves zero owned resources.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions