Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/sandbox/gotchas.md
1# Gotchas & Best Practices23## Common Errors45### "Container running indefinitely"67**Cause:** `keepAlive: true` without calling `destroy()`8**Solution:** Always call `destroy()` when done with keepAlive containers910```typescript11const sandbox = getSandbox(env.Sandbox, 'temp', { keepAlive: true });12try {13const result = await sandbox.exec('python script.py');14return result.stdout;15} finally {16await sandbox.destroy(); // REQUIRED to free resources17}18```1920### "CONTAINER_NOT_READY"2122**Cause:** Container still provisioning (first request or after sleep)23**Solution:** Retry after 2-3s2425```typescript26async function execWithRetry(sandbox, cmd) {27for (let i = 0; i < 3; i++) {28try {29return await sandbox.exec(cmd);30} catch (e) {31if (e.code === 'CONTAINER_NOT_READY') {32await new Promise(r => setTimeout(r, 2000));33continue;34}35throw e;36}37}38}39```4041### "Connection refused: container port not found"4243**Cause:** Missing `EXPOSE` directive in Dockerfile44**Solution:** Add `EXPOSE <port>` to Dockerfile (only needed for `wrangler dev`, production auto-exposes)4546### "Preview URLs not working"4748**Cause:** Custom domain not configured, wildcard DNS missing, `normalizeId` not set, or `proxyToSandbox()` not called49**Solution:** Check:501. Custom domain configured? (not `.workers.dev`)512. Wildcard DNS set up? (`*.domain.com → worker.domain.com`)523. `normalizeId: true` in getSandbox?534. `proxyToSandbox()` called first in fetch?5455### "Slow first request"5657**Cause:** Cold start (container provisioning)58**Solution:**59- Use `sleepAfter` instead of creating new sandboxes60- Pre-warm with cron triggers61- Set `keepAlive: true` for critical sandboxes6263### "File not persisting"6465**Cause:** Files in `/tmp` or other ephemeral paths66**Solution:** Use `/workspace` for persistent files6768### "Bucket mounting doesn't work locally"6970**Cause:** Bucket mounting requires FUSE, not available in `wrangler dev`71**Solution:** Test bucket mounting in production only. Use mock data locally.7273### "Different normalizeId = different sandbox"7475**Cause:** Changing `normalizeId` option changes Durable Object ID76**Solution:** Set `normalizeId` consistently. `normalizeId: true` lowercases the ID.7778```typescript79// These create DIFFERENT sandboxes:80getSandbox(env.Sandbox, 'MyApp'); // DO ID: hash('MyApp')81getSandbox(env.Sandbox, 'MyApp', { normalizeId: true }); // DO ID: hash('myapp')82```8384### "Code context variables disappeared"8586**Cause:** Container restart clears code context state87**Solution:** Code contexts are ephemeral. Recreate context after container sleep/wake.8889## Performance Optimization9091### Sandbox ID Strategy9293```typescript94// ❌ BAD: New sandbox every time (slow)95const sandbox = getSandbox(env.Sandbox, `user-${Date.now()}`);9697// ✅ GOOD: Reuse per user98const sandbox = getSandbox(env.Sandbox, `user-${userId}`);99```100101### Sleep & Traffic Config102103```typescript104// Cost-optimized105getSandbox(env.Sandbox, 'id', { sleepAfter: '30m', keepAlive: false });106107// Always-on (requires destroy())108getSandbox(env.Sandbox, 'id', { keepAlive: true });109```110111```jsonc112// High traffic: increase max_instances113{ "containers": [{ "class_name": "Sandbox", "max_instances": 50 }] }114```115116## Security Best Practices117118### Sandbox Isolation119- Each sandbox = isolated container (filesystem, network, processes)120- Use unique sandbox IDs per tenant for multi-tenant apps121- Sandboxes cannot communicate directly122123### Input Validation124125```typescript126// ❌ DANGEROUS: Command injection127const result = await sandbox.exec(`python3 -c "${userCode}"`);128129// ✅ SAFE: Write to file, execute file130await sandbox.writeFile('/workspace/user_code.py', userCode);131const result = await sandbox.exec('python3 /workspace/user_code.py');132```133134### Resource Limits135136```typescript137// Timeout long-running commands138const result = await sandbox.exec('python3 script.py', {139timeout: 30000 // 30 seconds140});141```142143### Secrets Management144145```typescript146// ❌ NEVER hardcode secrets147const token = 'ghp_abc123';148149// ✅ Use environment secrets150const token = env.GITHUB_TOKEN;151152// Pass to sandbox via exec env153const result = await sandbox.exec('git clone ...', {154env: { GIT_TOKEN: token }155});156```157158### Preview URL Security159Preview URLs include auto-generated tokens:160```161https://8080-sandbox-abc123def456.yourdomain.com162```163Token changes on each expose operation, preventing unauthorized access.164165## Limits166167| Resource | Lite | Standard | Heavy |168|----------|------|----------|-------|169| RAM | 256MB | 512MB | 1GB |170| vCPU | 0.5 | 1 | 2 |171172| Operation | Default Timeout | Override |173|-----------|----------------|----------|174| Container provisioning | 30s | `SANDBOX_INSTANCE_TIMEOUT_MS` |175| Port readiness | 90s | `SANDBOX_PORT_TIMEOUT_MS` |176| exec() | None (no default) | `timeout` option |177| sleepAfter | 10m | `sleepAfter` option |178179**Performance**:180- **First deploy**: 2-3 min for container build181- **Cold start**: 2-3s when waking from sleep182- **Bucket mounting**: Production only (FUSE not in dev)183184## Production Guide185186See: https://developers.cloudflare.com/sandbox/guides/production-deployment/187188## Resources189190- [Official Docs](https://developers.cloudflare.com/sandbox/)191- [API Reference](https://developers.cloudflare.com/sandbox/api/)192- [Examples](https://github.com/cloudflare/sandbox-sdk/tree/main/examples)193- [npm Package](https://www.npmjs.com/package/@cloudflare/sandbox)194- [Discord Support](https://discord.cloudflare.com)195