The Two-Word Bug Report: "crashing in a loop"
In the middle of an intensive benchmarking session, the user sends a message consisting of just three words:
crashing in a loop
That's the entire message. No greeting, no explanation, no request for action. Just a statement of fact, delivered with the brevity of someone who expects the recipient to immediately understand the full weight of the situation. And in the context of the conversation, those three words carry enormous meaning — they signal that the assistant's diagnosis was wrong, its fix failed, and the system remains broken.
The Context: A High-Stakes Speculation Tuning Session
To understand why this terse message is so significant, we need to trace the events leading up to it. The assistant had been engaged in an extensive performance tuning exercise for the Qwen3.5-122B-A10B model, deployed across four RTX PRO 6000 Blackwell GPUs using SGLang with Multi-Token Prediction (MTP) speculation. The goal was to find the optimal speculative_num_steps parameter — the number of future tokens the draft model predicts in each forward pass, which directly trades increased per-step compute for higher token acceptance rates.
The assistant had methodically worked through steps=1, 2, 3, 4, and 5, benchmarking each configuration and producing detailed comparison tables. The results were impressive: single-request throughput climbed from 123 tok/s at steps=1 to 277 tok/s at steps=4, and 282 tok/s at steps=5. The user, seeing this upward trajectory, asked at message 6522: "Try 10 steps to see if we unplateu" — a typo-laden but clear directive to push the speculation depth further and see if throughput would continue to rise or plateau.
The assistant complied, editing the systemd service file to set --speculative-num-steps 10, copying it to the remote server, and restarting the service. But this is where things began to unravel.
A Cascade of Misdiagnoses
What followed was a classic debugging spiral. The assistant checked the service status and found it had crashed and auto-restarted. It dug into the logs and initially hypothesized an OOM kill — the 11 draft tokens per request (steps + 1) consuming too much KV cache memory. But then it found logs showing the server had actually run successfully with steps=10, achieving 270-293 tok/s with an accept rate of 0.92. The crash, it concluded, was from its own systemctl stop command: systemd had sent SIGTERM, the server was gracefully exiting with pending benchmark requests, and after the 60-second TimeoutStopSec timer expired, systemd sent SIGKILL.
This seemed plausible. The assistant then observed a restart loop — the server would start loading, crash, and systemd would auto-restart it. It diagnosed this as zombie processes from the previous instance holding GPU memory, preventing the new instance from allocating. It executed a thorough cleanup: stopping the service, killing Python processes from the Proxmox host with kill -9, running fuser -k /dev/nvidia* to release GPU file handles, and confirming all four GPUs showed 0 MiB used. Confident the fix was complete, it started the service fresh and settled in to wait 120 seconds for the model to load (message 6540).
The User's Intervention
It was during this 120-second wait that the user sent the message. The assistant, still waiting for its sleep 120 to complete, had no way of knowing the fix had failed. The user, monitoring the system independently — perhaps watching systemctl status or observing that the service wasn't responding — could see the truth: the server was still crashing in a loop.
The message is a reality check. It tells the assistant: your diagnosis was incomplete, your cleanup didn't address the root cause, and the problem persists. The brevity is itself informative — it suggests the user expects the assistant to understand the situation without hand-holding, and it carries an implicit urgency: stop waiting and start debugging again.
Why the Assistant's Diagnosis Was Wrong
The assistant's mistake was a classic debugging error: it attributed the crash loop to a secondary effect (zombie processes holding GPU memory) rather than the primary cause (the steps=10 configuration itself being unsustainable). The zombie processes were real — they do accumulate when systemd's auto-restart fires before a previous instance has fully released GPU resources. But they were a symptom, not the root cause.
The actual root cause was likely that with speculative_num_steps=10, the speculative_num_draft_tokens was auto-adjusted to 11 (steps + 1). Each concurrent request now required KV cache space for 11 draft tokens in addition to the main model's tokens. This dramatically reduced the available KV cache slots, which in turn reduced max_running_requests and max_total_num_tokens. The server might have been able to start and serve a single request (as the logs showed), but under any real load — or even during the model loading process itself — memory pressure would cause it to crash.
The assistant had actually noted this effect earlier in the session: at steps=3, max_running_requests dropped to 17 (from 21 at steps=2), and max_total_num_tokens dropped to 295,931 (from 377,207). At steps=10, these numbers would be even more constrained, potentially making the server unstable even at idle.
The Deeper Significance
This message is a turning point in the conversation. It forces the assistant to abandon its current line of investigation and reconsider the problem from scratch. The assumption that "the server actually ran fine with steps=10" — based on log entries showing successful inference — was misleading. A server can process a few requests successfully and still be fundamentally unstable, especially when memory pressure builds gradually or when the model loading phase itself requires peak memory.
The message also reveals something about the collaboration dynamic. The user is not just a passive observer issuing high-level requests; they are actively monitoring the system and providing real-time feedback. When the assistant goes down a wrong path — spending time and compute on a flawed diagnosis — the user cuts in with a correction. The three-word message is an efficient signal: stop what you're doing, your premise is wrong.
Input and Output Knowledge
To understand this message, the reader needs to know: that the assistant had just performed a cleanup and was waiting for a fresh server start; that the server had been crashing in a restart loop prior to the cleanup; and that the assistant believed the cleanup had resolved the issue. The user's message directly contradicts that belief.
The knowledge created by this message is a correction to the assistant's mental model. The crash loop is not caused by zombie processes or stale GPU allocations. The steps=10 configuration itself is the problem — whether through insufficient KV cache memory, excessive draft token overhead, or some other resource constraint. The assistant must now re-examine its assumptions and find the true root cause.
Conclusion
"crashing in a loop" is a masterclass in concise technical communication. In three words, the user conveys: a status report (the server is down), a diagnosis (it's not a one-time crash but a recurring loop), a correction (your fix didn't work), and an implicit directive (debug this properly). It's the kind of message that only works between collaborators who share deep context — and in the opencode conversation, it works perfectly. The assistant understands immediately that its carefully constructed narrative about zombie processes and graceful shutdowns was wrong, and that the real work of diagnosing the steps=10 failure is just beginning.