Use this guide when executions behave unexpectedly and you need to identify whether the issue is in your code, runtime setup, policy configuration, or session lifecycle.
Diagram: Debugging workflow
1) Turn on observability first
CLI debug logs
isol8 run script.py --debug
Useful for:
- engine option resolution (
mode, network, limits)
- container lifecycle and pool behavior
- execution completion metadata (
exitCode, duration, truncated)
Server debug logs
isol8 serve --port 3000 --key "$ISOL8_API_KEY" --debug
Useful for:
- request metadata (
runtime, code length, sessionId)
- session reuse vs creation
- semaphore acquire/release
- auto-prune activity
2) Reproduce with a minimal command
Before deep analysis, reduce moving parts:
isol8 run -e "print('hello')" \
--runtime python \
--net none \
--no-stream \
--debug
Then add complexity one knob at a time:
- package installs (
--install)
- filtered network (
--net filtered, --allow, --deny)
- persistence (
--persistent, --persist)
- larger input/files
3) Inspect container state with --persist
--persist leaves execution containers running so you can inspect filesystem/process state.
isol8 run script.py --runtime python --persist --debug
Then inspect with Docker:
docker ps --filter "ancestor=isol8:python"
docker exec -it <container-id> sh
ls -la /sandbox
env
ps aux
--persist is for debugging and leaves containers running by design. Clean them up after investigation.
Cleanup:
4) Validate effective configuration
Many issues come from unexpected default/override values.
Confirm:
defaults.network, defaults.timeoutMs, defaults.memoryLimit
network.whitelist / network.blacklist
cleanup.autoPrune, cleanup.maxContainerAgeMs
maxConcurrent
5) Debug stream vs non-stream behavior
CLI streams by default. If debugging final output/result flags (truncated, final stderr), switch to non-stream mode:
isol8 run script.py --no-stream --debug
In non-stream mode CLI prints:
- final stdout/stderr
- truncation warning when output exceeded cap
- network logs (if present)
6) Debug network policy issues
For filtered mode connectivity checks:
isol8 run net_test.py \
--net filtered \
--allow "^api\\.github\\.com$" \
--log-network \
--debug \
--no-stream
What to verify:
- target host actually matches allow regex
- deny rules are not shadowing allow rules
networkLogs appear only when both are true:
network: filtered
logNetwork: true
7) Debug session and file issues (remote)
If files/sessions fail, verify sessionId usage and lifecycle:
- create/reuse session via
/execute with sessionId
- call
/file upload/download using same sessionId
- check prune settings if session disappears
curl -X POST http://localhost:3000/execute \
-H "Authorization: Bearer $ISOL8_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "debug-session-1",
"request": { "code": "print(1)", "runtime": "python" }
}'
8) Library-level debugging patterns
import { DockerIsol8 } from "@isol8/core";
const engine = new DockerIsol8({
mode: "ephemeral",
debug: true,
persist: true,
network: "none",
timeoutMs: 15000,
});
await engine.start();
const result = await engine.execute({
runtime: "python",
code: "print('debug run')",
});
console.log({
exitCode: result.exitCode,
durationMs: result.durationMs,
truncated: result.truncated,
containerId: result.containerId,
});
await engine.stop();
For remote client debugging:
import { RemoteIsol8 } from "@isol8/core";
const remote = new RemoteIsol8(
{
host: "http://localhost:3000",
apiKey: process.env.ISOL8_API_KEY!,
sessionId: "debug-session-remote",
},
{
timeoutMs: 20000,
network: "none",
}
);
await remote.start(); // validates /health reachability
const out = await remote.execute({ runtime: "python", code: "print('ok')" });
console.log(out.stdout);
await remote.stop(); // deletes session when sessionId is set
9) High-signal checks by failure class
Runtime selection
- explicitly pass
--runtime when extension detection is uncertain
- avoid inline Deno; run Deno code from file path (
.mts) in current adapter model
Resource pressure
- raise
--timeout for long workloads
- raise
--memory for OOM-like termination
- increase
--sandbox-size for large package/file workloads
Persistent mode behavior
- one persistent container supports one runtime
- local CLI process exit ends engine lifecycle
- for multi-call remote persistence, use stable
sessionId
Output surprises
- set
--no-stream to inspect final aggregate output path
- raise
--max-output when output is intentionally large
Related pages