Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SPACE: Troubleshooting

First identify which stage failed: local setup, API authentication, a sandbox operation, or a command stream. An accepted request, a running sandbox, and a successful command are three different outcomes.

Local installation

This section covers the Kind installation. Use the explicit kind-space-local context so diagnostics target that local deployment, not another cluster. If you selected another cluster name, replace the context accordingly.

SymptomCheck and action
required tool not on PATH: kind or command not found: tiltComplete Install and verify tools, including the Bash startup configuration and fresh-login check. The bring-up does not install tools.
Tools work in one terminal but not a new oneConfirm that $HOME/.local/bin is on PATH in the new Bash shell. Repeat the startup configuration and fresh-login check in Install and verify tools; another inline export alone will not fix future logins.
SSH disconnects during a buildReconnect to the same host and run tmux attach-session -t space-setup. Inspect the running command before starting anything else; if you did not use tmux, check whether the original build is still running before retrying.
Running setup from a MacUse a Linux x86_64 host with KVM and run the setup there over SSH. Installing the command-line tools on macOS does not satisfy the host requirements.
/dev/kvm or /dev/net/tun is missing, or storage setup failsCheck device access, nested virtualization, privileged Docker operations, loop devices, and btrfs support on the host.
Package installation failsInstall the packages named in the error, or provide root/non-interactive sudo access. Rerun the failed step rather than skipping it.
Pods remain pending or restartRun the commands below and inspect the first failing pod's events and container logs. Confirm the host supports the required privileged containers and storage operations.
seed:latest cannot be resolvedCheck space-seed-publish logs and completion. The seed must be built and published before sandbox creation.
Login rejects root@localUse the password selected before the bring-up (password by default). Confirm the bring-up completed and Tilt's provision-local-console resource succeeded; rerunning does not reset an existing password.
API or data plane refuses connectionsCheck service readiness: kubectl --context kind-space-local -n space get pods,endpoints,svc should show ready pods behind space-api-entry and space-data-plane-entry. localhost reaches them through the cluster's port mappings (docker port space-local-worker3); a cluster created before those mappings is refused by the bring-up with the command to recreate it. API reachability does not prove data-plane reachability.
curl: (52) Empty reply from serverA replica may have been replaced mid-request, or, for the UI and object storage, Tilt's port forward may be reconnecting after Tilt replaced its target pod. Check the forwarding logs before changing credentials.
kubectl --context kind-space-local -n space get pods
kubectl --context kind-space-local -n space get events \
  --sort-by=.metadata.creationTimestamp
kubectl --context kind-space-local -n space logs job/space-seed-publish
kubectl --context kind-space-local -n space \
  logs job/space-db-migrate -c migrate
tilt logs provision-local-console --tail 50

For an individual pod, use kubectl --context kind-space-local -n space describe pod <pod-name> and kubectl --context kind-space-local -n space logs <pod-name> -c <container-name>. Use --previous to read the previous instance's logs after a container restart.

Sandbox pods (space-sbx-…) run in their own namespace, sandboxes, not in space: list them and their events with kubectl --context kind-space-local -n sandboxes get pods,events. NetworkPolicies there admit only the API and cluster-controller on port 9800; kubectl --context kind-space-local -n sandboxes get networkpolicies shows them.

For an empty reply, inspect the Tilt resource that holds the forward (space-ui for port 3000, space-object-store for port 8333) for port-forward errors, and wait for its pod to be ready again before retrying:

for resource in space-ui space-object-store; do
  printf '\n== %s ==\n' "$resource"
  tilt logs "$resource" 2>&1 | grep -i 'port.forward' | tail -n 20
done

An empty reply does not establish whether a mutation reached the server. Inspect its outcome and retain the original request body and idempotency key before retrying.

If a port forward is absent, start the one you need in a separate terminal and leave it running. Each command below runs in the foreground, and requires its local port to be free.

kubectl --context kind-space-local -n space \
  port-forward --address=127.0.0.1 svc/space-ui 3000:3000
kubectl --context kind-space-local -n space \
  port-forward --address=127.0.0.1 svc/object-store 8333:8333

Sandbox and command failures

Use the Python example's read-only inspect action from Your first sandbox, with RUN_DIR set to the exact saved run directory. Keep the same exported endpoint settings and a current SPACE_API_TOKEN.

python3 examples/first_sandbox.py inspect "${RUN_DIR:?Set the saved run directory}"

This prints sandbox listings and the saved creation/deletion operations, sandbox, and running-process list. Operations report lifecycle progress or failure; the sandbox reports its current state and conditions. If a request failed before returning IDs, inspect its HTTP error and the saved request in state.json, rather than constructing an empty-ID URL.

SymptomCheck and action
Missing management token, 401, or 403Repeat authentication and verify authorization for the resource. Do not use a command attachment token for management requests.
Create is accepted but execution is not readyPoll the operation, confirm running, and check the process endpoint. Inspect operation errors and sandbox conditions before creating another sandbox.
Sandbox is paused, suspended, or stoppedWaiting alone will not restart it. Inspect its state, request the appropriate lifecycle action, and wait for readiness. See lifecycle behavior, including the default idle policy.
Command exists but has not startedAttach to its data-plane events URL. Creating the command session alone does not start the process.
Stream authentication failsUse attach.token, not SPACE_API_TOKEN, and the correct session URL. Check expiry and attach promptly after creating the command.
Example rejects an endpoint, events URL, or redirectUse HTTPS except for loopback HTTP. Check the data-plane origin and session ID; correct the configuration rather than removing destination or redirect checks.
HTTP stream succeeds but output is incompleteCheck for process_exited, its exit result, and any error or resync_required frame. A closed connection is not proof of successful execution.
Reconnect reports resync_requiredThe stream could not resume exactly: output from before the reconnect may be missing or repeated. Check that the client sends the last id it received exactly as received. A process that has written more than 2^33 - 1 output chunks always resumes this way. Inspect the saved event transcript and query the process only if it is still running. Rerun only if repeating the command's effects is safe.
Command exits nonzeroRead stderr and the exit result from the saved event transcript. Check that the executable and working directory exist inside the sandbox, not just on the host.
Single-process GET returns not_foundThis endpoint inspects a running or recently exited process, not historical command results. It returns not_found before attachment and once the sandbox no longer keeps the exit: 15 minutes after exit, sooner once many newer processes start, and right after exit on a sandbox from an older template.

Inspect a running process with GET /v1/sandboxes/{sandbox_id}/processes/{process_id}. An empty process list is expected after a command exits; use the saved event transcript to check its result. Keep a failed transcript for diagnosis, but review it for secrets before sharing it.

Timeouts mean different things

A client deadline limits how long the client waits; it does not cancel a lifecycle operation or establish that a process stopped. Inspect the resource before retrying or issuing another command.

LimitValueMeaning
Walkthrough API request30 seconds normally; 180 seconds for process readinessA whole-exchange Python deadline, not a server-side cancellation.
Walkthrough state polling5 minutes per target stateStops waiting, not the server-side operation.
Walkthrough event stream45 secondsStops reading the stream, not a reliable process-cancellation mechanism.
Command timeout30s in the example; none when omittedServer-side execution deadline; expiry terminates the process group.
Attachment token lifetime5 minutesSeparate from the command's execution timeout; observe the returned attachment expiry.
Default sandbox idle policy6 hours without access or command activitySuspends an idle sandbox rather than imposing a fixed lifetime.

The Python example uses Linux signals to bound whole requests and stream reads. Run it as an executable on the documented Linux host, not in a background Python thread.

Retry without duplicating work

For endpoints that declare a required Idempotency-Key, keep the original request body and key until the mutation's outcome is known. The Python example saves them in state.json. For a retry of the same action, resend the same body with the same key; changing the body under the same key causes an idempotency_conflict.

Process kill and signal do not deduplicate requests with Idempotency-Key. Do not blindly retry an ambiguous outcome; inspect the process and its event stream first, because a repeat can apply the action again.

Check a returned operation ID before resending a lifecycle mutation. A new key represents a new request and can create another sandbox or command; do not use a new key merely because a connection timed out.

Read the API error's code, message, details, request_id, and retryable fields. Correct non-retryable errors first, and use bounded backoff for retryable errors without discarding the original key.

A file route's 404 (not_found) whose details include {"key": "resource", "value": "path"} means the sandbox is yours and the path inside it does not exist, so there is no need to look the sandbox up again. Without that detail, the sandbox itself was not found or is not yours; the two answer alike.

rate_limited is not the only 429. A POST /v1/sandboxes that would exceed the organization's or the user's sandbox limit gets 429 quota_exceeded with retryable: false and no Retry-After: resending it unchanged fails the same way until a sandbox is deleted or an in-flight create ends. See SPACE_NATIVE_ORG_SANDBOX_LIMIT in docs/configuration.md.

A command create's 400 (invalid_request) whose details include {"key": "field", "value": "pty"} means it asked for a pty with Accept: text/event-stream. Server-sent events cannot drive a terminal, so drop the pty, or create the command without that header and attach over WebSocket.

A sandbox that is at capacity, or shutting down, can refuse a request before doing any of its work: a retryable 429 (rate_limited) or 503 with Retry-After. That request did nothing, though an earlier attempt of the same action may have; wait at least that long and resend it with the same body and key, or reattach to the same session. SPACE does not retry these refusals for you. A timeout leaves the outcome unknown, and it is retryable only where the endpoint deduplicates by its key. Lifecycle operations and command creation deduplicate for 24 hours; file writes, batch writes, and renames only for 60 seconds after they complete, and not across a restart of the sandbox's agent, so retry them promptly or check the file first. File mkdir, remove, and change tracking do not deduplicate: their timeouts are not retryable, so check the sandbox's state before repeating them.

When reporting a problem, include the source revision, failing step, request ID, relevant sandbox/operation/process/session IDs, and sanitized error or event output. Exclude bearer tokens, passwords, private keys, and sensitive command environment values.