Repository navigation
Description
Area
[Engine] (speed, kernels, models, the server and API)
Desktop app, Terminal or source?
Source (START-HERE.bat, setup.sh or a build)
What happened
While serving two alternating long conversations (~310K tokens each) on a two-gpu layer split, the engine exited 21 times in 4 h 08 min (exit code 1, 2026-10-19 19:20:21 .. 23:02:57), each time right after a conversation checkpoint save ran out of host RAM. Every exit was followed by the runtime reloading the model (~45 s) and the next request succeeding, so the service looked healthy throughout.
The engine log shows the same three lines each time:
strata serve: checkpoint save: conversation snapshot running-state copy: out of memory
strata serve: saving a checkpoint part failed
and the runtime reports:
[strata] the engine stopped unexpectedly (exit code 1). The engine exited (code 1) after it reported: saving a checkpoint part failed - please report it at github.com/Niko1221/Strata/issues with the log. The next request starts the engine again.
[strata] done: 0 tokens in 2 s (0.0 tok/s) (error, cancel=False)
[strata] the engine had stopped (exit code 1); starting it again (a minute or two) ...
The part I did not expect: the parking admission gate refuses the very same conversation moments earlier, on the same host, and it is right.
strata serve: conversation cache: skip parking (physical RAM admission; need 2915 MiB plus 1536 MiB floor, 2437 MiB available, source meminfo; evicted 0, 0 still parked)
strata serve: conversation cache: parked 310875 tokens in 190.5 ms; parked=1 bytes=6022875424 evictions=0 snapshot_bytes=6022875424 reused_kv_bytes=4740933120
So parking declines cleanly when the RAM is not there, and then the checkpoint writer copies anyway and takes the engine down with it. Numbers on this box at the time of the failure: engine RSS 51.7-54.8 GiB of 62.7 GiB RAM, one parked snapshot of a 310K-token conversation 5.61 GiB (6022875424 bytes). With --conversation-cache-slots 3 that is a planned ~17 GiB of snapshots on the few GiB that are left.
What I expected instead: a conversation checkpoint is an optimization, the same way parking is. If the copy cannot be made, drop that checkpoint (or that conversation's entry) and serve the request, rather than exiting the engine. As it stands a refused optimization becomes a 45 s outage, every parked conversation is lost, and in-flight requests fail.
Client-visible damage in the same window: done: 0 tokens in 2 s (0.0 tok/s) (error, cancel=False), and one request died after 1519 generated tokens.
Also worth knowing for anyone monitoring this: systemd never sees it. The reported unit stayed active, NRestarts=0, Result=success for the whole 4 h 08 min run, because the engine is a child of serve/server.py and the restart happens inside the runtime. The only reliable signal is journalctl -b -u strata | grep -c "engine stopped unexpectedly".
Smallest steps or command that reproduce it
- Two-gpu layer split with long contexts, conversation caching on with more slots than the RAM can hold:
--layer-split 25 --max-context 524288 --kv int8 --spec 4 \
--conversation-cache-mib 12288 --conversation-cache-slots 3 \
--conversation-cache-min-free-mib 1536 --session-save-reclaim
-
Serve two conversations of ~300-310K tokens alternately from two clients (mine came from two connections on the same LAN host). In my log the last three failures arrived exactly 6:00 apart.
-
The failures stop when the slot count fits the RAM. With
--conversation-cache-slots 1and nothing else changed, the same two clients, the same ~310K requests: 13 requests over 13.5 min, 0 engine exits, 0 out-of-memory lines (largest prompt 311,068 tokens). Service memory peak 58 GiB with 1.9 GiB swap, against 59.2 GiB + 6.8 GiB swap before.
There is one other exit in the same boot with the same wording, from a different path: verify: instantiate: out of memory also exits the engine (1 occurrence). Same shape, same expectation.
Reproduction status
Reproduced locally
Strata version
Source install, v0.1.45, commit 477ac13c, engine/BUILD.json "version": "0.1.45" (GET /props reports Strata 0.1.45).
Graphics card, memory and system
2 x RTX 3080 20 GB (sm_86), 62.7 GiB RAM (MemTotal: 65728088 kB), CachyOS, kernel 7.2.8-1-cachyos, NVIDIA driver 615.71.09, CUDA 13. zram for swap (62.7 GB, 1.2 G in use), since that matters below.
Model, size and settings
Qwen3.8-Flash-Next IQ3_S (native pack), --max-context 524288 (--rope-scaling yarn --rope-scale 2.0, trained 262144), --kv int8, --spec 4, --mtp, --vision, --expert-cache auto, --layer-split 25, --vram-reserve-mib 512, --pcie-frac 0.20, --conversation-cache-mib 12288, --conversation-cache-slots 3, --conversation-cache-min-free-mib 1536, --session-save-reclaim.
Logs
The failure, with the admission refusal that preceded it (engine log, one occurrence):
strata serve: conversation cache: skip parking (physical RAM admission; need 2715 MiB plus 1536 MiB floor, 3442 MiB available, source meminfo; evicted 0, 0 still parked)
strata serve: conversation cache: restored 306479 tokens (live) in 836.2 ms; parked=0 bytes=5029207144
strata serve: prompt 306705 tokens = 306479 reused + 226 read in 2119 ms (106.7 tok/s), 348 generated in 4309 ms (80.8 tok/s), drafts accepted 184 of 236, 6 checkpoints
strata serve: conversation cache: parked 307054 tokens in 220.0 ms; parked=1 bytes=5872999448 evictions=0 snapshot_bytes=5872999448 reused_kv_bytes=4678049664
strata serve: checkpoint save: conversation snapshot running-state copy: out of memory
strata serve: saving a checkpoint part failed
Exit codes for the whole boot: 21 x (exit code 1) on this path, 1 x (exit code -15) which was my own systemctl restart.
Snapshot sizes observed for 309-310K-token conversations: 5.61-6.02 GB (bytes=6022875424, bytes=5872999448).
Checked against 0.2.0-beta / engine 0.1.45.3 (static analysis, not run)
I did not run 0.2.0-beta on this box, so this part is from the source, not from a measurement:
src/core/conversation_state.cppis byte-identical between thev0.1.45tree andv0.2.0-beta(diffis empty), so the copy that fails is the same code.- The call site in
src/program/generate.cppis unchanged in behaviour:if (!checkpoint_save(part, stage_ss, g)) { e = "saving a checkpoint part failed"; return false; }, still propagating to the caller'sif (!saved) { e = "saving a conversation checkpoint failed" + ckpt_why; return false; }. - Nothing in the 0.2.0 release notes mentions conversation-cache checkpoint memory.
If a memory admission check for this path did land somewhere I did not look, I would rather be corrected than file a duplicate, and I will happily re-test on a 0.2.0-beta build.
One thing that may be relevant to how you want to fix it
The RAM guard already computes exactly what the parking path needs (need N MiB plus M MiB floor, K MiB available, source meminfo), and it consults MemAvailable plus cgroup limits. The checkpoint writer appears to consult nothing. zram is not a safety net here: it is compressed RAM, so the spike has nowhere to go, and the copy is a cudaMemcpy to host memory that returns CUDA_ERROR_OUT_OF_MEMORY rather than an allocator failure the caller could catch earlier.
Activity
github-actions commentedon Oct 20, 2026
Thanks for the issue. To keep the tracker readable, every item needs an area prefix in the title and the parts of the issue form filled in. This one is missing:
Edit the issue (title and description) and this note goes away on its own. If it is still missing parts in 5 days it will be closed, which is not a rejection: fix it and comment
/reopen.Details: CONTRIBUTING.md
github-actions commentedon Oct 20, 2026
Thanks, this follows the format now.
sanastasiou commentedon Oct 25, 2026
Same crash here, on a 2× RTX 3090 layer split. Adding data points, one of which may matter for #4073's theory.
Setup
--max-context 524288 --batch-groups auto --pipeline-windows 2 --prompt-cache-every 2048 --trim-stage-weights--conversation-cache-min-free-mib 40960, 48 prompt checkpoints.Frequency
Always the same two lines, right after a conversation was parked:
The runtime then logs
the engine stopped unexpectedly (exit code 1) ... The next request starts the engine again.Observations
/healthkeeps answering{"status": "ok", "loaded": false}. Our leaf stayed down for ~1.5 h until we noticed. Suggestions:statusreflect a dead engine.What would fix it for us: a failed checkpoint save should drop that checkpoint (and maybe free the oldest parked conversation), not exit the engine. Even better, reserve the staging buffer for the running-state copy up front, so the copy can't hit out-of-memory mid-request.
Related: #4073 (same model, 2× 3090, 0.2.3.1).
KodeMunkie commentedon Oct 26, 2026
Same issue here on a Docker deployment serving an agent, with a two-GPU layer split. Adding another hardware/configuration data point.
Environment
4b9e05a2a806.7.0.0-38-generic, NVIDIA driver595.99.02.huihui-ai/Huihui-Qwen3.8-Flash-Next-abliterated-v2-GGUF,UD-IQ4_XS.Relevant effective engine settings:
Observed failure
The retained engine log contains three occurrences with this model and the 512 MiB reserve configuration. There are ten occurrences overall across earlier models/configurations too.
Two examples from the current configuration:
The server then reports that the engine exited with code 1 and that the next request starts it again. Affected requests report zero output tokens.
Memory observations
Startup logs for an affected run reported only 205 MiB free on the first GPU and 77 MiB on the second, before subsequent graph captures.
Host-side checks during the investigation found approximately 6–154 MiB free on the two serving GPUs. System RAM availability was approximately 37–43 GiB, with almost no swap used. These are investigation-time samples, not measurements captured at the exact failing CUDA call.
This supports investigating GPU/driver resource pressure, but does not establish which allocation failed or why. I cannot distinguish stream creation, copy staging or another allocation from the existing error message.
serve: a checkpoint whose copy runs out of memory is skipped, it no l…
conversation copies: the private copy streams and events are handed b…
serve: an idle batch slot's decoded conversation is parked before an …
Later-card VRAM: audit fixes for failed allocations, the reserve arit…
Conversation cache: skip a restore only when a card would have to cre…
Niko1221 commentedon Oct 27, 2026
Thank you. Fixed in 0.2.7: A checkpoint whose copy runs out of memory is skipped, it no longer ends the engine.
Release: https://github.com/Niko1221/Strata/releases/tag/v0.2.7
fix(engine,serve): port four upstream v0.2.7 fixes
serve: a checkpoint whose copy runs out of memory is skipped, it no l…
conversation copies: the private copy streams and events are handed b…
Conversation cache: skip a restore only when a card would have to cre…
remote stage: a failed checkpoint save still ends the request
sycl: re-migrate the port to upstream 0.1.54 (from its last re-migrat…
serve: チェックポイントの写しがメモリ不足のときは飛ばし、エンジンを止めない(upstream f62589f)
engine: Niko1221#3416 の組、AVX-512 の gather の行、会話の退避とグラフの解放を移植する(Issue #51