# How Do I Tell if a Sandbox Resume Restored Memory or Cold-Booted?

> Read memoryRestored after every resume. true means memory came back and processes kept running. false means the sandbox booted from disk, and resumeReason says why (cpu_mismatch, resized, no_memory_snapshot or restore_failed). Inside the guest, compare /proc/sys/kernel/random/boot_id with a saved copy. On a cold boot, restart services and re-warm caches.

Source: https://sandboxer.com/guides/detect-a-cold-boot-after-resume. Updated 2026-10-27.

**Short answer:** Read memoryRestored after every resume. true means memory came back and processes kept running. false means the sandbox booted from disk, and resumeReason says why (cpu_mismatch, resized, no_memory_snapshot or restore_failed). Inside the guest, compare /proc/sys/kernel/random/boot_id with a saved copy. On a cold boot, restart services and re-warm caches.

A resume usually restores the VM's memory, so your processes carry on (see [pause and resume with memory](/guides/pause-and-resume-a-sandbox-with-memory)). Sometimes it boots from disk instead. Your files are kept, but nothing is running. An agent that assumes its dev server, REPL or cache is still there will then fail in confusing ways. This page shows how to tell the two cases apart and what to do in each.

## The signals at a glance

We ran both cases on a `small` sandbox on 2026-10-27: a plain `sbx stop --wait` + `sbx resume`, then a stop and `sbx resume --type default`.

| Signal | Memory resume | Cold boot (resize) |
| - | - | - |
| `memoryRestored` (API, `sbx info --json`) | `true` | `false` |
| `resumeReason` | `null` | `"resized"` |
| CLI note on `sbx resume` (terminal) | none | `Resumed from disk: files are intact, running processes were not kept (resized).` |
| `/proc/sys/kernel/random/boot_id` | unchanged | new value |
| `/proc/uptime` | keeps counting (39.4 s) | starts again (2.8 s) |
| Process started before the stop | alive, same PID | gone |
| File in `/tmp` | still there | gone |
| File in your home directory | still there | still there |
| Resume time | 1.4 s | 3.4 s |

`memoryRestored` is `null` before a sandbox's first resume, and on forks. When it's `false`, `resumeReason` is one of the four values in the [snapshots docs](/docs/snapshots#resume): `cpu_mismatch` (no machine with the sandbox's CPU type was free in time), `resized`, `no_memory_snapshot` or `restore_failed`. We could only force `resized` on prod. The other three depend on the platform's state, so treat any `false` the same way.

## Check from outside: the API or CLI

The orchestrator that resumed the sandbox should check right away. With the CLI:

```bash
sbx resume $id >/dev/null
read restored reason < <(sbx info $id --json | jq -r '.sandbox | "\(.memoryRestored) \(.resumeReason // "none")"')
echo "restored=$restored reason=$reason"
```

```text
restored=false reason=resized
```

With the REST API, the same two fields are on the sandbox object:

```bash
curl -sS https://sandboxer.com/api/v1/sandboxes/$id \
  -H "Authorization: Bearer $SANDBOXER_API_KEY" | jq -c '.sandbox | {memoryRestored, resumeReason}'
```

```text
{"memoryRestored":true,"resumeReason":null}
```

The `ready` event that `sbx resume --json` prints already carries the full sandbox, including `memoryRestored`, so a script that reads the event stream needs no extra call. A human-readable `sbx resume` prints a note only for a cold boot. It prints nothing extra when memory was restored.

## Check from inside: the boot id

Code running in the sandbox can't see the API fields without a key, and it may not know a resume happened at all. The Linux kernel gives each boot a random id in `/proc/sys/kernel/random/boot_id`. A memory resume keeps the same kernel, so the id stays the same. A cold boot gets a new one. Save it and compare:

```bash
mkdir -p ~/bin && cat > ~/bin/boot-check <<'EOF'
#!/bin/sh
# Prints warm or cold, then remembers this boot.
now=$(cat /proc/sys/kernel/random/boot_id)
last=$(cat ~/.last-boot-id 2>/dev/null)
echo "$now" > ~/.last-boot-id
if [ "$now" = "$last" ]; then echo warm; else echo cold; fi
EOF
chmod +x ~/bin/boot-check
```

Keep the saved copy in your home directory, not `/tmp`. In our cold boot, `/tmp` came back empty. What we saw across the three runs:

```text
first run                           cold   (no saved id yet)
after sbx resume                    warm   uptime 7.08 s, server PID 554 still listed
after sbx resume --type default     cold   uptime 2.74 s
```

The ids themselves, from another run:

```text
before stop:          45b7df5a-4d1f-4c77-932f-ce80599c9927
after memory resume:  45b7df5a-4d1f-4c77-932f-ce80599c9927
after resize resume:  edfaa86e-d636-43c9-af19-f63aac2433d4
```

Uptime is a weaker signal. A low uptime suggests a cold boot, but a sandbox that ran for only a few seconds before its stop also has a low uptime after a memory resume (7.08 s above). Use the boot id.

## What to do in each case

| You see | What's still there | Do this |
| - | - | - |
| `memoryRestored: true` / same boot id | Processes, open files, in-memory caches, shell state | Nothing for processes. Re-check anything that depends on elapsed time (next section) |
| `memoryRestored: false` / new boot id | Files in your home directory and on disk, enabled systemd units | Start what you started by hand (dev servers, REPLs, `tmux`), rebuild in-memory caches, rerun warm-up requests, and treat jobs that were running as lost |
| `resumeReason: "cpu_mismatch"` and you need the processes | Same as above | Next time, resume with `sbx resume --require-memory`. It waits up to 30 minutes for a matching machine instead of booting from disk |

An agent loop can make the restart step automatic:

```bash
if [ "$restored" != true ]; then
  sbx exec $id --detach "python3 -m http.server 8000"   # start your service again
  # then rerun your warm-up step, e.g. a first request or a cache build
fi
```

A better fix is to need no restart step at all. Run long-lived services as enabled systemd units, so a cold boot starts them for you (see [services that should always run](/docs/long-running#services-that-should-always-run)). Then the check only decides whether to re-warm caches and redo lost work.

`--require-memory` can't be combined with `--type`: a new size always boots from disk. The CLI's cold-boot note still suggests `--require-memory` after a `resized` resume. Ignore it in that case. Moving to a smaller size isn't supported yet (create a new sandbox and copy your files). Our `sbx resume --type small` after moving to `default` returned `400 type_too_small` ("The sandbox's data does not fit the small disk.").

## Timers after a memory resume

The wall clock is corrected on resume, so `date` and `time.time()` are right. Elapsed-time clocks may not count all of the stopped time. In our test on 2026-10-27, a 2-minute stop moved the guest's monotonic clock forward by only about 62 seconds:

```text
before stop    real 1793097486.33  mono 3.46   boot 3.46
after resume   real 1793097610.91  mono 65.17  boot 65.17
```

The wall clock moved 124.6 s, and the monotonic clock (and `CLOCK_BOOTTIME`) 61.7 s. A `sleep 90` started just before the stop fired 152 seconds of wall time after it started, 28 seconds after the resume. In a shorter, 32-second stop, the monotonic clock moved about the same as the wall clock. Don't rely on either behavior. If a deadline, timeout or lease must hold across a stop, compare wall-clock timestamps (`date +%s`, `time.time()`) rather than monotonic ones, or recheck it when your boot check runs.

## FAQ

### Which is more reliable, memoryRestored or the boot id?

Both told the truth in every run. Use `memoryRestored` from the orchestrator, because it also gives the reason. Use the boot id inside the sandbox, where you have no API key or don't know a resume happened.

### Can I force a cold boot to test my recovery code?

Yes. Stop the sandbox, then resume it at a larger size with `sbx resume $id --type default`. It reports `memoryRestored: false` and `resumeReason: "resized"`. Moving to a smaller size isn't supported yet, so test on a throwaway sandbox.

### Do files survive a cold boot?

Files on the disk do, including your home directory. `/tmp` was empty after our cold boot, so keep anything you need in your home directory.

### Does an idle auto-pause behave the same way?

Yes. A wake after [idle auto-pause](/guides/idle-auto-pause-and-wake-on-use) is a resume, so it sets `memoryRestored` and `resumeReason` the same way.

## Related

- [Pause and resume a sandbox with its memory](/guides/pause-and-resume-a-sandbox-with-memory)
- [Run a long job in a cloud sandbox](/guides/run-a-long-job-in-a-cloud-sandbox)
- [Persistent or ephemeral sandboxes for agents](/guides/persistent-or-ephemeral-sandboxes-for-agents)
- [Snapshots and resume](/docs/snapshots)
