Skip to content

qwen4exp: GGML_ABORT ("maskless selected-key attention was not taken by a QSA kernel") on KV-cache exhaustion under --kv-unified with concurrent slots #85

Open

Description

@randomm

Name and Version

Built from this repo at commit 8c1c282ec (2026-09-17, current master HEAD as of this report), build tag 11195. HIP/ROCm backend, on a retained-PM4 ROCm runtime build (pwilkin/rocm-systems ilintar-experiments @ 7dda3ac6cf), built 2026-09-21.

Operating systems

Linux (Fedora 43, kernel 6.18.16)

GGML backends

HIP

Hardware

Ryzen AI Max+ 395 / gfx1151 (Strix Halo), 128GB unified memory

Models

Qwen3.8-Flash-Next, UD-IQ3_XXS quant (unsloth), + a separate MTP draft-model sidecar (mtp-Qwen3.8-Flash-Next-Q8_0.gguf, unsloth, non-shared variant) via --spec-type draft-mtp.

Problem description & steps to reproduce

Running llama-server with --parallel 3 -c 262144 --kv-unified (native context, shared KV pool across 3 slots) under real concurrent agentic-coding traffic (multiple simultaneous requests, several with 50k-120k+ token contexts). Not synthetic — this is our normal production serving config for this model on this hardware.

When the shared KV pool fills (one slot's prefill reaching ~124k tokens while another slot is concurrently active/growing), decode hits the "no free space in KV cache" retry path and shrinks batch size across attempts: 2048 → 1024 → 512. At the n_batch = 512 retry, ggml_cuda_flash_attn_ext receives a tensor shape that satisfies dst->src[5] && !dst->src[3] (a selected-key op with no mask) but is not recognized by either ggml_cuda_flash_attn_ext_qsa_decode_supported or ggml_cuda_flash_attn_ext_qsa_prefill_supported, so it falls through to the GGML_ABORT guard in ggml/src/ggml-cuda/fattn.cu:778 and the process dies (SIGABRT).

This reliably brings the whole llama-server process down (confirmed via llama-swap's upstream-process-exited-unexpectedly + auto-restart, and via journalctl / container exec_died), not a single-request failure.

Reproduction command (production config)

llama-server -m Qwen3.8-Flash-Next-UD-IQ3_XXS-00001-of-00003.gguf \
  -ngl 999 -fa 1 --load-mode none --parallel 3 -c 262144 -ctk q8_0 -ctv q8_0 --kv-unified \
  --jinja --metrics -ub 2048 -b 2048 -ctk f16 -ctv f16 \
  --spec-draft-model mtp-Qwen3.8-Flash-Next-Q8_0.gguf --spec-type draft-mtp --spec-draft-n-max 3 \
  --spec-draft-p-min 0.0 --lazy-mode on-direct --checkpoint-min-step 16384 --cache-ram 4096

Note -ctk/-ctv are specified twice (q8_0 then f16) — this is intentional in our config; the launcher hardcodes q8_0 and we override to f16 via extra flags, and llama.cpp takes the last occurrence (confirmed via the startup log's own deprecation warning, which is expected/harmless here).

I don't yet have an isolated minimal repro (e.g. exact token counts / timing to force it synthetically) — this was caught live via production traffic with full logging. Happy to help build one if useful, e.g. a script that fills the KV pool across N slots near the ctx ceiling and forces the batch-shrink path.

Relevant log output

17.27.144.707 E init_batch: failed to prepare attention ubatches
17.27.144.721 W decode: failed to find a memory slot for batch of size 2048
17.27.144.757 W srv        decode: failed to find free space in the KV cache, retrying with smaller batch size, off = 0, n_batch = 1024, ret = 1
17.30.359.107 E init_batch: failed to prepare attention ubatches
17.30.359.113 W decode: failed to find a memory slot for batch of size 1024
17.30.359.163 W srv        decode: failed to find free space in the KV cache, retrying with smaller batch size, off = 1024, n_batch = 1024, ret = 1
17.30.365.586 E init_batch: failed to prepare attention ubatches
17.30.365.590 W decode: failed to find a memory slot for batch of size 1024
17.30.365.629 W srv        decode: failed to find free space in the KV cache, retrying with smaller batch size, off = 1024, n_batch = 512, ret = 1
/opt/llama.cpp/ggml/src/ggml-cuda/fattn.cu:783: flash_attn_ext: maskless selected-key attention was not taken by a QSA kernel (node_710): q [256,512,24,1] f32 nb 24576/1024, k [256,262144,2,1] f16 nb 2/1024/512, v f16 nb 1024/512, ids [2051,512,1,1] nb 8204, src6 0 src7 0 p4 0 dst contiguous 1
/usr/local/lib64/libggml-base.so.0(+0x6874) [0x7fe54c961874]
/usr/local/lib64/libggml-base.so.0(ggml_print_backtrace+0x1e0) [0x7fe54c961ce0]
/usr/local/lib64/libggml-base.so.0(ggml_abort+0x11d) [0x7fe54c961e8d]
/usr/local/lib64/libggml-hip.so.0(_Z24ggml_cuda_flash_attn_extR25ggml_backend_cuda_contextP11ggml_tensor+0x1ee6) [0x7fe551774a06]
/usr/local/lib64/libggml-hip.so.0(+0x4d54c70) [0x7fe5517d2c70]
/usr/local/lib64/libggml-hip.so.0(+0x4d471a7) [0x7fe5517c51a7]
/usr/local/lib64/libggml-base.so.0(ggml_backend_graph_compute_async+0x14) [0x7fe54c97b0e4]
/usr/local/lib64/libggml-base.so.0(ggml_backend_sched_graph_compute_async+0x875) [0x7fe54c9810b5]
/usr/local/lib64/libllama.so.0(_ZN13llama_context13graph_computeEP11ggml_cgraphb+0xa0) [0x7fe55260b5a0]
/usr/local/lib64/libllama.so.0(_ZN13llama_context14process_ubatchERK12llama_ubatch14llm_graph_typeP22llama_memory_context_iR11ggml_status+0x1ca) [0x7fe55260f30a]
/usr/local/lib64/libllama.so.0(_ZN13llama_context6decodeERK11llama_batch+0x37b) [0x7fe55261421b]
/usr/local/lib64/libllama.so.0(llama_decode+0xe) [0x7fe552615d1e]

The q [256,512,24,1], k [256,262144,2,1], ids [2051,512,1,1] shapes are from the moment of the abort: k's second dim (262144) matches our full context ceiling, and the shrunk batch size (512) shows up in q's second dim — consistent with this being specifically the retry-at-reduced-batch-size path producing a shape the QSA dispatch checks don't cover.

System state at the time

Concurrent host memory pressure was also present (main system RAM ~120Gi/123Gi used, swap 7.9Gi/8.0Gi) though this looks like a kernel-dispatch/shape-coverage bug rather than an OOM — the abort is a deliberate GGML_ABORT guard, not a memory allocation failure, and system memory pressure was likely just a side effect of the KV pool growing this large rather than the direct trigger.

First Bad Commit

Unknown — this is the first time we've hit it; our build (8c1c282ec) is current master. Possibly present since the QSA dispatch kernels were introduced; haven't bisected.

Activity

  1. joshvoigts commented on Sep 30, 2026

    @joshvoigts

    I'm seeing the same error and crash. Seems to occur near the end (or possibly at the end of the maximum context).

    Build: strix-llama.cpp=12643af64 (master), rocm_systems=7dda3ac6cf (ilintar-experiments)

    gfx1151 / HIP, -c 262144 --kv-unified, n_slots=1, MTP draft (mtp-Qwen3.8-Flash-Next-shared-Q8_0.gguf), not --parallel.

  2. klucsik commented on Sep 30, 2026

    @klucsik

    Second data point + the exact trigger band (and a proposed gate fix)

    Production, gfx1151 / HIP, build 12643af64 (= master at the time), -c 262144 --kv-unified -np 2 --flash-attn on --cache-type-k f16 --cache-type-v f16 --fit off, MTP+ngram-mod speculation:

    [47401] /opt/llama.cpp/ggml/src/ggml-cuda/fattn.cu:783: flash_attn_ext: maskless selected-key
    attention was not taken by a QSA kernel (node_762): q [256,853,24,1] f32 nb 24576/1024,
    k [256,262144,2,1] f16 nb 2/1024/512, v f16 nb 1024/512, ids [2051,853,1,1] nb 8204,
    src6 0 src7 0 p4 0 dst contiguous 1
    

    The child instance exited with status 1 and the multi-model supervisor respawned it — which is why the container restartCount stays 0 and the Pod never looks unhealthy. Slot occupancy at the abort: 153,781 + 108,067 = 261,848 of 262,144 cells used, i.e. two concurrent slots filling the unified cache from opposite ends.

    The gate and the kernels disagree

    qwen4exp_use_block_selection() (src/models/qwen4exp.cpp:812) admits the maskless route up to n_kv <= 16777216. The kernels that must execute the resulting op are far stricter, and they disagree with each other by 4 cells:

    kernel depth bound why query cap
    qsa_prefill k->ne[1] <= 262140, %4 == 0 whole blocks packed as uint16 with 0xFFFF reserved as the empty sentinel → 65535 * ratio(4) q->ne[1] >= 128
    qsa_decode k->ne[1] <= 262144 no block packing q->ne[1] <= 512

    llama_kv_cache::get_n_kv() pads the used extent to 256 (n_pad_cur = max(n_pad, 256)), so a 262144-cell cache exposes exactly one depth past the prefill bound: every used count in 261889..262144 reports n_kv = 262144. The rung below it is 261888, which is inside the bound.

    fattn.cu tries decode, then prefill. So the fatal combination is narrow and fully determined:

    maskless route taken (n_stream == 1) AND n_kv == 262144 (cache padded onto the last rung) AND ubatch > 512 tokens → no kernel accepts the op → GGML_ABORT.

    Every prefill clause that the abort string exposes passes on our node (853 ≥ 128, ids->ne[0]=2051 ≤ 2560, ids->nb[1]=8204 so %4==0, k->nb[1]=1024/k->nb[2]=512 so %16==0, f16 K/V, head 256, 24 = 12×2 GQA, dst contiguous, src6/src7 null, p4 0, bias/softcap 0) — the only two clauses not printed are the q->data/k->data/ids->data alignment tests, which are satisfied in practice because these are graph-allocated buffers. So the op is 4 keys of depth away from being servable, and decode can't take it only because of the 512-query cap. Note 262144 % 4 == 0, so this isn't an artifact of the alignment clause: the two caps genuinely differ, and the llama-side gate is checked against neither.

    This also explains #85's own node — and predicts it is partially fixed

    #85 and @joshvoigts's report both show q=512 at depth 262144. On those builds (8c1c282ec, before 9bc06f5f7 "qsa : take 1..512 queries in the per-query decode kernel") the decode cap was 8, so a 512-token ubatch fell through both gates for the same structural reason. After 9bc06f5f7, decode accepts q <= 512 at 262144 — so I'd expect your exact node to be served now; worth re-testing on current master. The band that survives on master is q > 512, which is what we hit.

    Proposed fix: gate on the intersection of the kernel bounds

    --- a/src/models/qwen4exp.cpp
    +++ b/src/models/qwen4exp.cpp
    @@
    +// The selected depth must also fit the kernel that will run the op: qsa_prefill indexes whole blocks as uint16 and
    +// reserves 0xFFFF as the empty sentinel, so at ratio 4 it can address 65535*4 -> 262140 keys. qsa_decode is looser
    +// (262144), but it only takes up to 512 queries, so a deeper ubatch that lands past the prefill bound has no kernel
    +// at all and fattn aborts. Keep this in sync with the k->ne[1] bound in ggml/src/ggml-cuda/qsa-prefill.cu.
    +static constexpr int64_t QSA_MASKLESS_MAX_KV = 262140;
    +static_assert(QSA_MASKLESS_MAX_KV%4 == 0, "qsa_prefill requires a multiple-of-4 key count at its depth bound");
    +
     static bool qwen4exp_use_block_selection(bool blk_bias, int64_t n_stream, int64_t ratio, int64_t n_kv,
             const llama_ubatch & ubatch, const llama_cparams & cparams, const llama_hparams & hparams,
             ggml_type type_k, ggml_type type_v) {
         return blk_bias && n_stream==1 && ratio>1 && hparams.indexer_top_k%ratio==0 &&
    -        n_kv>hparams.indexer_top_k+ratio-1 && n_kv<=16777216 && ubatch.token &&
    +        n_kv>hparams.indexer_top_k+ratio-1 && n_kv<=QSA_MASKLESS_MAX_KV && ubatch.token &&

    Cost is one padded rung: used cells 261889..262144 served by a >512-token maskless ubatch fall back to the masked route (261888 is a multiple of 4, so prefill alignment is respected; decode at q <= 512 and depth 262144 stays on the QSA path). Because get_n_kv() quantises to 256, this is a single rung, not a sliding window.

    Hardening alternatives, if you'd rather not tighten the model-side gate:

    • raise the prefill bound to 262144 by padding the last pack and dropping the %4 requirement, or
    • align the two kernel caps so no reachable depth is accepted by neither, and assert the invariant (n_kv == 262144 ⇒ only q <= 512 may be maskless).

    Relation to #115 and #110

    Rebuild-free workaround

    -c 261888 (256-aligned, so GGML_PAD(n_ctx, 256) leaves it; n_ctx_seq == 261888 <= 262140 under --kv-unified). The cache can never report the fatal rung, for 0.1 % of context. Not yet applied on our side (we have no write access to the ConfigMap), so this is a proposed mitigation rather than a verified one.

    Repro recipe

    Two concurrent sessions on -c 262144 --kv-unified -np 2 --flash-attn on --cache-type-k f16 --cache-type-v f16 --fit off, n_swa == 0. Drive combined used cells past 261888 (we were at 261,848), then send a >512-token incremental prompt to the slot with the shorter prefix so it doesn't split into <=512 chunks. --ubatch-size 1024 makes it deterministic. Full 787 s log available.

    Confirmed present in 12643af64; fattn.cu, qsa-decode.cu and qsa-prefill.cu are byte-identical in current 8b7217718, and no branch in the repo relaxes the 262140 bound (0636c9aee introduced it).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions