Handle failures and unexpected state¶
Symptom |
Check or action |
|---|---|
Authentication or profile error |
Check the URL, token, and AI project; see Connection sources. |
Unknown image tag |
Import the image on the selected endpoint; see Import a Docker image. |
A file from the previous command disappeared |
For explicit |
Work disappeared after Python restarted |
Resume the same |
Explicit async session has no |
Await |
|
Supply a base image for a new tree, or |
A completed result did not become current |
A newer local selection exists; select the saved result explicitly as shown below. |
|
Use |
Note
Async snippets with top-level await run inside an async function or a notebook
that supports it. For a standalone script, use the asyncio.run(main()) structure
from Your first sandbox.
Fail a sandbox workflow on a nonzero exit¶
A nonzero command exit returns a result. Calling run_workflow() below raises
inside the context, discards unsaved changes, and closes the VM.
from contree_sdk import create_sandbox_session
def run_workflow() -> None:
with create_sandbox_session(image="tag:alpine:latest") as sandbox:
result = sandbox.run(shell="exit 7")
if result.state.exit_code != 0:
raise RuntimeError(f"Command failed with exit code {result.state.exit_code}")
from contree_sdk import create_sandbox_session
async def run_workflow() -> None:
async with create_sandbox_session(image="tag:alpine:latest") as sandbox:
result = await sandbox.run(shell="exit 7")
if result.state.exit_code != 0:
raise RuntimeError(f"Command failed with exit code {result.state.exit_code}")
Advanced: a command returned a nonzero exit code¶
This is a process result, so run() returns it without raising FailedOperationError.
The example uses disposable execution and leaves the session image unchanged.
from contree_sdk import ContreeSession, create_sandbox_session
with create_sandbox_session(session_type=ContreeSession, image="tag:alpine:latest") as session:
result = session.run(shell="echo failed >&2; exit 7", disposable=True)
if result.state.exit_code != 0:
print(result.stderr)
print("exit:", result.state.exit_code)
from contree_sdk import ContreeAsyncSession, create_sandbox_session
async with create_sandbox_session(session_type=ContreeAsyncSession, image="tag:alpine:latest") as session:
result = await session.run(shell="echo failed >&2; exit 7", disposable=True)
if result.state.exit_code != 0:
print(result.stderr)
print("exit:", result.state.exit_code)
Commands save by default. Inspect the exit code before continuing. A saved command can have changed files even when its process exits nonzero. Roll back explicitly if those changes should not remain selected.
Advanced: select a late result¶
A completed operation retains its original parent. If local navigation or another operation changes the selected position, committing the result saves a sibling without selecting it. To save and select that result, give it a local branch name:
from contree_sdk import ContreeSession, create_sandbox_session
with create_sandbox_session(session_type=ContreeSession, image="tag:alpine:latest") as session:
operation = session.spawn(shell="echo candidate > /value.txt")
session.run(shell="echo newer > /value.txt")
operation.wait()
session.commit_result(operation, branch="recovered", title="Recovered result")
print(session.image_uuid)
from contree_sdk import ContreeAsyncSession, create_sandbox_session
async with create_sandbox_session(session_type=ContreeAsyncSession, image="tag:alpine:latest") as session:
operation = await session.spawn(shell="echo candidate > /value.txt")
await session.run(shell="echo newer > /value.txt")
await operation.wait()
await session.commit_result(operation, branch="recovered", title="Recovered result")
print(session.image_uuid)
Choose a fresh recovery branch name. The newer branch remains intact. The recovery branch selects the completed operation’s image; it does not merge the two filesystems.
Waiting failed, timed out, or was cancelled¶
Operation.wait() attempts cancellation when waiting raises and keeps the original
exception. A cancelled operation raises InterruptedError; an operation with no
successful result raises FailedOperationError. Client transport errors can also
propagate. Cleanup is best effort: retain the operation UUID if you need to inspect
its server status afterward.
A subprocess wait timeout does not itself terminate the whole operation. Use its
operation’s signal() or cancel(), or leave the operation context to shut it down.
See Advanced: control a running sandbox and SDK exceptions.
Advanced: catch an operation failure¶
If the server cannot complete the operation, the SDK raises FailedOperationError
and leaves history unchanged. Keep the operation UUID to investigate the failure:
from contree_sdk import ContreeSession, create_sandbox_session
from contree_sdk.exceptions import FailedOperationError
with create_sandbox_session(session_type=ContreeSession, image="tag:alpine:latest") as session:
try:
session.run("echo", args=["hello"])
except FailedOperationError as error:
print("failed operation:", error.operation_uuid)
from contree_sdk import ContreeAsyncSession, create_sandbox_session
from contree_sdk.exceptions import FailedOperationError
async with create_sandbox_session(session_type=ContreeAsyncSession, image="tag:alpine:latest") as session:
try:
await session.run("echo", args=["hello"])
except FailedOperationError as error:
print("failed operation:", error.operation_uuid)