Hub Python Library documentation
Sandboxes
Sandboxes
The Sandbox API is experimental. Its API and behavior may change without notice. Shared sandboxes are intended for workloads within the same trust boundary; use dedicated sandboxes for workloads that do not trust each other.
Check out the Sandboxes guide to learn how to use them.
Sandbox
class huggingface_hub.Sandbox
< source >( id: strserver: _SandboxServerlocal_id: str | Noneowns_sandbox: boolowns_server: boolsandbox_token: str | None = None )
An isolated cloud machine running on Hugging Face Jobs.
The Sandbox API is experimental. Its API and behavior may change without notice.
Create a dedicated one with Sandbox.create() (one job per sandbox), or get many cheap shared ones from a SandboxPool.
Reattach to a running sandbox from anywhere with Sandbox.connect(). Use as a context manager to terminate it on exit:
>>> from huggingface_hub import Sandbox
>>> with Sandbox.create(image="python:3.12") as sbx:
... print(sbx.run("python --version").stdout)Release the local HTTP client without terminating the sandbox. Idempotent.
No-op for pool sandboxes (the client belongs to the pool’s host).
Reattach to a running sandbox from anywhere, using only its id.
create
< source >( image: str = 'python:3.12'flavor: str = 'cpu-basic'idle_timeout: int | float | str | None = 600env: dict[str, typing.Any] | None = Nonesecrets: dict[str, typing.Any] | None = Nonevolumes: typing.Optional[typing.List[huggingface_hub._space_api.Volume]] = Nonenamespace: str | None = Noneforward_hf_token: bool = Falselabels: dict[str, str] | None = Nonestart_timeout: float = 120.0token: str | None = None )
Parameters
- image (
str, optional, defaults to"python --3.12"): Any Docker image with/bin/sh(Docker Hub orhf.co/spaces/...). - flavor (
str, optional, defaults to"cpu-basic") — Hardware flavor, e.g."cpu-basic","a10g-small". Seehf jobs hardware. - idle_timeout (
intorfloatorstr, optional, defaults to600) — Auto-shutdown after this much inactivity (no API calls, no running processes). Defaults to 10 minutes; passNoneto disable. Note that a foreground command is not currently counted as activity, so a singlerun()that takes longer than this without other API traffic can have its sandbox shut down under it — raise the timeout (or passNone) for long single commands. - env (
dict[str, Any], optional) — Environment variables available in the sandbox. - secrets (
dict[str, Any], optional) — Secret environment variables (encrypted server-side). - volumes (
List[Volume], optional) — HF repos/buckets to mount, see Volume. - namespace (
str, optional) — User or org namespace to run under (defaults to current user). - forward_hf_token (
bool, optional, defaults toFalse) — If True, your HF token is injected asHF_TOKEN(opt-in). - labels (
dict[str, str], optional) — Labels to attach to the underlying HF Job. - start_timeout (
float, optional, defaults to120.0) — Max seconds to wait for the sandbox to become ready. - token (
str, optional) — HF token override.
Create a dedicated sandbox (one HF Job) and block until it is ready (~7s on cpu-basic).
Each sandbox is a full isolated VM, so this is the right choice for GPU workloads or untrusted code. To fan out many cheap CPU sandboxes instead, use SandboxPool.
The job runs with a fixed 24h maximum lifetime; idle_timeout is the real
keeper — an idle sandbox shuts itself down well before that.
The image only needs /bin/sh. The sandbox server is downloaded at startup with wget/curl if available, otherwise read off an always-mounted server bucket (which
adds ~2-3s to cold start, so shipping wget/curl keeps it fast).
List the background processes of this sandbox.
Returns the processes started with Sandbox.run()(..., background=True); stop one
with SandboxProcess.kill(). Recently completed processes stay listed (with running=False and their exit_code); the server keeps a bounded number of them, so a
sandbox that has run thousands of short commands will not list them all.
proxy_url_for
< source >( port: int | strpath: str = '/'scheme: str = 'https://' ) → str
Parameters
- port (
intorstr) — The port (pool: the<port>of the unix socket) the inner server listens on. - path (
str, optional, defaults to"/") — Path on the inner server to point at, e.g."/ws". - scheme (
str, optional, defaults to"https --//"): URL scheme to build the link with. Defaults to"https://"; pass"wss://"for a WebSocket client (the proxy is protocol-agnostic, so only the client-side scheme changes).
Returns
str
a URL like https://<job_id>--49983.hf.jobs/v1/.../proxy/8000/ws (or
wss://... with scheme="wss://").
Public URL that proxies through to a server running inside this sandbox.
Requests to the returned URL are forwarded by the in-job sandbox server to a
server you started in the sandbox on port, including WebSocket (ws(s)://)
upgrades and streamed responses. Pair it with proxy_headers for auth.
How the sandbox must listen on port:
- Pool / shared sandbox: it cannot bind a TCP port (Landlock), so bind a unix socket at
$SBX_PROXY_DIR/<port>.sock(theSBX_PROXY_DIRenv var is set in every sandbox). E.g.uvicorn app:app --uds $SBX_PROXY_DIR/8000.sock. - Dedicated sandbox: bind a normal TCP port on
127.0.0.1:<port>. (You can also expose the port directly via the job proxy without going through here.)
run
< source >( cmd: typing.Union[str, typing.List[str]]shell: bool | None = Noneenv: dict[str, typing.Any] | None = Nonecwd: str | None = Nonetimeout: float | None = Nonestdin: str | None = Noneon_stdout: typing.Optional[typing.Callable[[str], NoneType]] = Noneon_stderr: typing.Optional[typing.Callable[[str], NoneType]] = Nonecheck: bool = Truecapture_output: bool = Truebackground: bool = False )
Parameters
- cmd (
strorList[str]) — A shell command string (run with/bin/sh -c) or an argv list (exec’d directly). - shell (
bool, optional) — Force the execution mode instead of inferring it from the type ofcmd.Trueruns through/bin/sh -cand requirescmdto be a string;Falseexec’scmddirectly and requires it to be an argv list.None(default) infers from the type. Set it explicitly to avoid the type-driven footgun (e.g.["echo hi"]being exec’d as a single program named"echo hi"). - env (
dict[str, Any], optional) — Extra environment variables for this command. - cwd (
str, optional) — Working directory. - timeout (
float, optional) — Kill the command (whole process group) after this many seconds. - stdin (
str, optional) — Data to write to the command’s stdin. - on_stdout (
Callable[[str], None], optional) — Callback invoked with stdout chunks as they arrive. - on_stderr (
Callable[[str], None], optional) — Callback invoked with stderr chunks as they arrive. - check (
bool, optional, defaults toTrue) — If True, raiseSandboxCommandErroron non-zero exit. - capture_output (
bool, optional, defaults toTrue) — If True, accumulate stdout/stderr into the returned result. PassFalsewhen you only wanton_stdout/on_stderr: output is then handed to the callbacks and dropped, so a command producing gigabytes does not have to fit in memory.result.stdout/result.stderrare empty in that case. - background (
bool, optional, defaults toFalse) — If True, start the command detached and return a SandboxProcess right away instead of waiting for it and returning a SandboxCommandResult.
Run a command in the sandbox and wait for it, streaming output live.
With background=True the command is started detached and run returns a SandboxProcess immediately, without waiting for it to finish — handy for
servers and other long-running processes. List them later with Sandbox.processes() and stop one with SandboxProcess.kill(). The streaming/wait-only options
(timeout, stdin, on_stdout, on_stderr, check) don’t apply in that mode.
Returns: a SandboxCommandResult (with exit_code, stdout, stderr, duration_ms), or a SandboxProcess when background=True.
SandboxPool
class huggingface_hub.SandboxPool
< source >( image: str = 'python:3.12'flavor: str = 'cpu-basic'sandboxes_per_host: int = 50warm_up: int = 1max_hosts: int | None = Nonename: str | None = Noneidle_timeout: int | float | str | None = 600namespace: str | None = Nonestart_timeout: float = 120.0adopt_hosts: str = 'own'token: str | None = None_connect_mode: bool = False )
A fleet of shared “host” jobs, each packing many landlock-isolated sandboxes.
The Sandbox API is experimental. Its API and behavior may change without notice.
Pooled sandboxes are for workloads inside one trust boundary. A pooled sandbox is a uid plus a Landlock ruleset inside a shared VM — not a VM of its own — and every sandbox on a host shares that host’s auth token and its privileged control plane. Use a pool to fan out your own code cheaply. For mutually distrusting workloads, use Sandbox.create(), which gives each one its own VM. The specific gaps are listed under “Known limitations” in the sandbox conceptual guide.
One host is one billed HF Job (a VM); it runs the sandbox server and multiplexes
up to sandboxes_per_host lightweight sandboxes, isolated from each other by
uid + the Landlock LSM. This makes large fan-outs cheap (the VM cost is shared
across all its sandboxes) and fast (creating a sandbox is ~one proxy round-trip
once a host is warm). Best for many parallel CPU sandboxes such as RL rollouts;
for GPU or strong VM-level isolation between mutually-distrusting workloads, use Sandbox.create() instead.
The constructor pre-provisions warm_up hosts (default 1) and blocks until they are
ready; further hosts are then provisioned on demand as sandboxes are requested, and all
are torn down on close() (or when idle, via idle_timeout). The user never manages jobs:
>>> from huggingface_hub import SandboxPool
>>> with SandboxPool(image="python:3.12", flavor="cpu-basic", warm_up=2) as pool:
... boxes = [pool.create() for _ in range(100)] # packed across the warm hosts
... print(boxes[0].run("echo hi").stdout)
hicreate() makes one sandbox at a time: it reuses a host that still has free
capacity before booting a new one, so you grow on demand as work arrives. To avoid
a cold start on the first few calls, pre-provision hosts with warm_up (or warm). Warm hosts are discovered via job labels, so reuse works across
processes too (a fresh pool with the same image/flavor/name attaches to
hosts an earlier run left behind):
>>> pool = SandboxPool(image="python:3.12")
>>> sbx = pool.create() # finds a warm host (here or in another process), else boots oneRelease the pool. Idempotent.
For a pool we created, this terminates all host jobs (and therefore all their
sandboxes). For a connect()‘d handle it only releases the local HTTP clients: the
shared hosts may be serving other clients, so — like Sandbox.connect() — leaving a with block must not tear them down. Terminate a connected pool’s hosts explicitly
with hf sandbox pool delete <id>.
Only hosts this handle started are cancelled. A host discovered via labels may be serving another process’ sandboxes, so it is released rather than terminated.
Raises SandboxError if a host job could not be cancelled, naming the jobs that
are still running — they keep billing, and their cache entries are kept so they stay
discoverable. When close() is reached through __exit__ with an exception already
in flight, the failure is logged instead, so it cannot mask the original error.
connect
< source >( pool_id: strnamespace: str | None = Noneadopt_hosts: str = 'own'token: str | None = None )
Parameters
- pool_id (
str) — The id returned when the pool was first created. - namespace (
str, optional) — Namespace to search for the pool’s hosts (defaults to yours). - adopt_hosts (
str, optional, defaults to"own") — Which hosts may be attached to. See SandboxPool. Reattaching to a pool whose hosts another member of the namespace started needs"namespace". - token (
str, optional) — HF token override.
Reattach to a running pool by id, from any machine — no local state needed.
Finds a running host labelled with pool_id and rebuilds the pool’s config
(image/flavor/density/host-idle) from that host job’s spec and env vars, returning
a SandboxPool ready to create() more sandboxes — packing onto the running
hosts, or booting a duplicate (same config) when they are full.
Raises SandboxError if no running host is found (a pool stops existing once
all of its hosts are gone — idle-timed-out or killed).
create
< source >( env: dict[str, typing.Any] | None = Noneidle_timeout: int | float | str | None = 600forward_hf_token: bool = False )
Parameters
- env (
dict[str, Any], optional) — Environment variables for this sandbox (each sandbox gets its own). - idle_timeout (
intorfloatorstr, optional, defaults to600) — Per-sandbox idle timeout — a sandbox is evicted from its host after this much inactivity (no API calls, no running process). Distinct from the host idle timeout. PassNoneto disable. - forward_hf_token (
bool, optional, defaults toFalse) — If True, inject your HF token asHF_TOKENin the sandbox (opt-in). Unlike a dedicated sandbox’ssecrets, a pooled sandbox’s env is delivered to the host server at creation (never stored in the host job), so it doesn’t appear in any job’s metadata.
Create one sandbox, provisioning a host if needed.
Reuses a host with free capacity (this pool’s, or a warm host found via job labels
/ the local cache) before booting a new one, so a create() against a warm host
costs ~one round-trip. Call it repeatedly to fan out; use warm_up (or warm)
to pre-provision hosts and avoid a cold start on the first calls. If a host fills
up under us (another process packed it) or a cached host is gone, the sandbox is
re-placed on another host (or a fresh one).
Ensure num_hosts empty host(s) are running and leave them running. Returns the
pool’s host job ids.
Used to “create” a pool up front: the hosts carry the pool label and config (in
their env vars), so a later SandboxPool.connect(pool_id) (even from another
machine) finds them and spawns sandboxes without a cold start. The hosts keep
billing until killed or idle.
Adopts hosts already running for this pool (found via job labels) before booting,
so a warm() after connect() — or a repeated warm() — tops up to num_hosts instead of duplicating live hosts and blowing past max_hosts.
Data structures
SandboxCommandResult
class huggingface_hub.SandboxCommandResult
< source >( exit_code: int | Nonestdout: strstderr: strsignal: int | None = Nonetimed_out: bool = Falseduration_ms: int = 0 )
Result of a command executed in a sandbox with Sandbox.run().
SandboxProcess
class huggingface_hub.SandboxProcess
< source >( id: str | Nonepid: intcmd: typing.Union[str, typing.List[str]]_sandbox: Sandboxtag: str | None = Nonestarted_at_ms: int | None = Nonerunning: bool = Trueexit_code: int | None = None )
A background process started in a sandbox with Sandbox.run()(..., background=True).
List a sandbox’s processes with Sandbox.processes() and stop one with SandboxProcess.kill().
Recently completed processes stay in the listing (the server keeps a bounded number of
them), so running and exit_code tell whether a process is still alive or already
exited (as of when it was listed).
Terminate the background process. Idempotent.
Returns whether this call is what stopped it: False means it had already
exited or been terminated, which is not an error.
Note that a descendant which detaches with setsid() leaves the signalled
process group and outlives this call. Delete the sandbox to be certain
everything it started is gone.
FileEntry
class huggingface_hub._sandbox.FileEntry
< source >( name: strpath: strtype: typing.Literal['file', 'dir', 'symlink']size: intmtime_ms: int | None = Nonemode: str = '' )
A file or directory inside a sandbox.
Errors
SandboxError
class huggingface_hub.errors.SandboxError
< source >( message: strstatus_code: int | None = None )
Base exception for sandbox operations (see huggingface_hub.Sandbox).
SandboxCommandError
class huggingface_hub.errors.SandboxCommandError
< source >( cmdresult )
Raised when a command run in a sandbox exits with a non-zero code.