Principle:OpenHands OpenHands Sandbox Cleanup
| Knowledge Sources | |
|---|---|
| Domains | Cloud_Infrastructure, Runtime_Management |
| Last Updated | 2026-02-11 21:00 GMT |
Overview
Sandbox Cleanup is the principle of gracefully terminating cloud sandboxes and releasing provider resources, with conditional preservation for debugging purposes.
Description
Cloud sandboxes consume provider resources (compute, storage, network) for the duration of their existence. When an agent session ends -- whether through successful completion, error, or timeout -- the runtime must ensure that the sandbox is properly destroyed to prevent resource leaks. At the same time, developers and operators sometimes need to inspect a sandbox post-mortem for debugging, so the cleanup process must support conditional preservation.
OpenHands implements a resource cleanup pattern across all four third-party runtimes. Each runtime's close() method follows this general sequence:
- Check preservation conditions -- Determine whether the sandbox should be kept alive based on configuration flags or environment variables.
- Stop internal processes -- Shut down the action execution server and any other running processes inside the sandbox.
- Destroy the sandbox -- Call the provider's SDK to terminate and delete the sandbox resource.
- Clean up local state -- Reset internal references, close HTTP connections, and release any local resources.
Each provider has its own preservation mechanism:
- Daytona checks the DAYTONA_KEEP_SANDBOX environment variable. If set, the sandbox is left running for debugging.
- E2B skips sandbox destruction if attach_to_existing was True during initialization, preserving sandboxes that were not created by this session.
- Modal destroys the sandbox unconditionally via the Modal SDK's terminate method.
- Runloop supports a rm_all_containers flag that controls whether all associated containers are removed during cleanup.
The cleanup process must be robust against partial failures. If the sandbox has already been destroyed (e.g., due to a provider timeout), the close method should handle the resulting errors gracefully rather than raising exceptions.
Usage
Sandbox Cleanup is invoked at the end of an agent session, either explicitly by the orchestrator or automatically via context managers or shutdown hooks. It should also be called in error-handling paths to ensure resource release even when the session terminates abnormally.
Theoretical Basis
The resource cleanup pattern ensures deterministic resource release with optional preservation for debugging.
RESOURCE CLEANUP PATTERN:
method close():
IF should_preserve_sandbox():
LOG "Keeping sandbox alive for debugging"
RETURN
TRY:
CALL provider_sdk.destroy_sandbox(sandbox_id)
CATCH ProviderError:
LOG warning "Sandbox may already be destroyed"
RESET internal state (sandbox_ref = None, http_client = None)
PROVIDER-SPECIFIC PRESERVATION CONDITIONS:
Daytona:
should_preserve = os.environ.get("DAYTONA_KEEP_SANDBOX") is not None
E2B:
should_preserve = self.attach_to_existing is True
Modal:
should_preserve = False (always destroys)
Runloop:
should_preserve = not self.rm_all_containers
LIFECYCLE GUARANTEE:
1. After close() returns, no provider resources are held
(unless preservation is active).
2. close() is idempotent: calling it multiple times is safe.
3. close() does not raise exceptions for already-destroyed sandboxes.
The pattern emphasizes that resource cleanup is a critical reliability concern. A leaked sandbox can accumulate provider charges and consume quota, making robust cleanup essential for production deployments.