BerriAI/litellm · error · NotImplementedError
adelete_sandbox must be implemented by provider
Error message
adelete_sandbox must be implemented by provider
What it means
BaseSandboxConfig.adelete_sandbox() is the abstract teardown hook for destroying a sandbox container; it must return bool. The base class raises NotImplementedError to force provider implementations. Encountering it means the delete path ran against the base or an incomplete custom config, so the container was NOT deleted (leaked resources).
Source
Thrown at litellm/llms/base_llm/sandbox/transformation.py:80
async def arun_code(
self,
*,
container: ContainerHandle | str,
code: str,
api_key: str | None = None,
**kwargs,
) -> CodeExecutionResult:
raise NotImplementedError("arun_code must be implemented by provider")
async def adelete_sandbox(
self,
*,
container: ContainerHandle | str,
api_key: str | None = None,
**kwargs,
) -> bool:
raise NotImplementedError("adelete_sandbox must be implemented by provider")
async def _read_capped_lines(self, response: httpx.Response) -> list[str]:
lines: Final[list[str]] = []
total = 0
async for line in response.aiter_lines():
total += len(line.encode("utf-8"))
if total > SANDBOX_MAX_OUTPUT_BYTES:
raise ValueError(
f"Sandbox output exceeded {SANDBOX_MAX_OUTPUT_BYTES} bytes; aborting to avoid unbounded memory use."
)
lines.append(line)
return lines
View on GitHub (pinned to 6c2dcb801b)
Solutions
- Implement `async def adelete_sandbox(self, *, container, api_key=None, **kwargs) -> bool` in your custom config.
- Switch to a fully implemented provider (OpenSandbox/E2B) if you did not intend to write a custom one.
- Until fixed, manually delete leaked containers via the provider's dashboard/API.
Example fix
# before
class MySandbox(BaseSandboxConfig):
pass
await sandbox.adelete_sandbox(container=h) # raises; container leaks
# after
class MySandbox(BaseSandboxConfig):
async def adelete_sandbox(self, *, container, api_key=None, **kwargs) -> bool:
resp = await self._client.delete(f"/containers/{container.id}")
return resp.status_code in (200, 204) Defensive patterns
Strategy: try-catch
Validate before calling
from litellm.llms.base_llm.sandbox.transformation import BaseSandboxConfig assert type(cfg).adelete_sandbox is not BaseSandboxConfig.adelete_sandbox, "adelete_sandbox not implemented"
Type guard
from litellm.llms.base_llm.sandbox.transformation import BaseSandboxConfig
def supports_delete_sandbox(cfg: BaseSandboxConfig) -> bool:
return type(cfg).adelete_sandbox is not BaseSandboxConfig.adelete_sandbox Try / catch
try:
ok = await cfg.adelete_sandbox(container=handle)
finally:
if not ok:
record_leaked_container(handle.id) # ensure cleanup is trackable Prevention
- Wrap sandbox lifecycle in try/finally so delete failures don't lose the handle id.
- Run periodic reconciliation against the provider API to catch leaked containers.
When it happens
Trigger: Calling the sandbox delete/cleanup API when the active provider config does not override adelete_sandbox — custom subclasses or a provider fallback to BaseSandboxConfig.
Common situations: Custom provider implementers who implemented create/run but not delete; cleanup code (finally blocks, GC hooks) hitting the stub and leaking billed containers.
Related errors
- validate_environment must be implemented by provider
- acreate_sandbox must be implemented by provider
- arun_code must be implemented by provider
- Sandbox output exceeded {SANDBOX_MAX_OUTPUT_BYTES} bytes; ab
- get_complete_url must be implemented by provider
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/7b8dd433de41f232.
Report an issue: GitHub.