Skip to content

fix(server): restore prompt tokens from v2 blob in DECODE_APPLY - #69

Merged
ddvnguyen merged 1 commit into
hydra-forkfrom
fix/506-p100-decode-stall
Jul 29, 2026
Merged

ddvnguyen merged 1 commit into
hydra-forkfrom
fix/506-p100-decode-stall

Conversation

@ddvnguyen

Copy link
Copy Markdown
Owner

Closes ggml-org#506

Root Cause

In the DECODE_APPLY handler (async phase of the DECODE 0x43 path), slot->prompt_clear(false) clears slot->prompt.tokens before loading KV state via llama_state_seq_set_data. After the KV restore, the token list is never restored.

When the subsequent COMPLETION task runs update_slots():

  1. slot.prompt.tokens is empty (cleared, never restored)
  2. The n_common decision compares empty stored tokens vs N incoming tokens → n_common = 0
  3. n_past = 0 (else branch of n_common decision)
  4. pos_next = slot.prompt.tokens.pos_next(0) = 0
  5. seq_rm(ctx_tgt, slot.id, 0, -1) — wipes the entire KV cache that was just loaded
  6. Slot stalls at n_past=0, n_decoded=0 for the full timeout window

The STATE_PUT handler (old HTTP-completion path) correctly parses the v2 blob header and restores tokens (lines 3357-3362). The DECODE_APPLY handler did not.

Fix

Parse the v2 blob header in DECODE_APPLY to:

  1. Extract the token list from the blob header and restore slot->prompt.tokens
  2. Skip past the v2 header before passing raw KV data to llama_state_seq_set_data
  3. Set slot->just_restored = true so the CHECKPOINT_SEARCH path uses the cached n_past

The fix is backward-compatible: if the coordinator sends raw KV data (no v2 header), the code falls through to the existing behavior.

Evidence

Clean re-test (2026-07-29, build db1654c):

  • restore_kv_ms=571 — STATE_PUT/DECODE RPC completed successfully
  • P100 slot: n_past=0, n_decoded=0 for 291 seconds until timeout
  • No crash, no error logged — the KV was loaded then silently destroyed by seq_rm

Build

CUDA 13.2 sm_86+sm_120 build: 480/480 targets passed.

DECODE_APPLY calls prompt_clear(false) before loading KV state, which
wipes slot->prompt.tokens.  The subsequent COMPLETION task's n_common
decision then finds 0 stored tokens, computes n_past=0, and
seq_rm(slot, 0, -1) destroys the KV that llama_state_seq_set_data
just loaded — causing the decode slot to stall at n_past=0 for the
full timeout window.

Parse the v2 blob header (if present) to restore the token list, skip
past the header before calling llama_state_seq_set_data, and set
just_restored so the CHECKPOINT_SEARCH path uses the cached n_past.

Closes ggml-org#506

@ddvnguyen ddvnguyen left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the diff and root-cause explanation — this checks out. DECODE_APPLY's prompt_clear(false) wiping slot->prompt.tokens before the v2-blob-aware KV restore, leaving n_common's decision logic with nothing to match against, is a precise explanation for the exact symptom in ggml-org#506 (restore RPC succeeds, n_past stuck at 0 for the full timeout, no crash). The fix correctly detects the v2 blob (same 0x02 magic byte check already used in the STATE_PUT handler at server-context.cpp:3276), restores the token list, skips the optional checkpoint sub-blob before advancing past the header, and sets just_restored so the downstream CHECKPOINT_SEARCH path uses the cached n_past instead of recomputing from an empty token list.

One non-blocking note: this duplicates the v2-header-parsing logic that already exists inline in the STATE_PUT handler (~line 3273-3300) rather than factoring it into a shared helper. Not a regression — STATE_PUT's version is also inline, so this follows existing style rather than introducing a new pattern — but worth a follow-up cleanup given there are now two independent inline copies of this parsing logic that could drift out of sync.

Build passes per the PR. No blocking concerns — good catch and a well-targeted fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Move the third-party build / deploy scripts to a separate repository

1 participant