Repository navigation
Description
Environment
| FLM version | v0.9.43 (flm --version → FLM v0.9.43; /api/version → {"version":"0.9.43"}) — latest release |
| OS | Ubuntu 24.04, glibc 2.39 (GLIBC 2.39-0ubuntu8.7) |
| CPU/NPU | AMD Ryzen AI MAX+ 395 "Strix Halo", NPU aie2p (6×8), single /dev/accel/accel0 |
| NPU firmware | 1.1.2.65 |
| XDNA driver | amdxdna 2.23.0_20260413 (XRT 2.23.0) |
| Model | qwen3-it:4b (Qwen3-4B-Instruct-2507-NPU2, Q4_1, 32k ctx) |
| Launch flags | flm serve qwen3-it:4b --pmode turbo --ctx-len 32768 --prefill-chunk-len 8192 --port 52625 |
| Linked libs | libxrt_coreutil.so.2, libboost_program_options.so.1.83.0, libgomp.so.1 (OpenMP) |
Symptom
flm serve (running as a long-lived server) aborts intermittently with glibc heap-corruption diagnostics on stderr, immediately after the model-list banner, then the supervisor restarts it (each restart reloads the NPU model). Observed signatures:
double free or corruption (out)
corrupted size vs. prev_size while consolidating
malloc(): unaligned tcache chunk detected
[FLM] Using custom model list path: .../share/flm/model_list.json
The abort is a SIGABRT from glibc's allocator, not an OOM (no exit code 137, memory was not exhausted) and not a config/port error. It occurred repeatedly during a burst of ~10 concurrent clients hitting the server in a short window, then stopped once traffic serialized (the current process has since been stable for 8+ hours under light load).
Trigger (best hypothesis)
- Concurrent-request bursts. The crashes clustered when ~10 independent clients issued
/v1/chat/completionsrequests near-simultaneously. Under steady/serialized traffic we have not reproduced it. --ctx-len 32768appears within limits (the model advertises 32k; community reports run--ctx-len 32000fine), so context length alone does not look like the cause.--prefill-chunk-len 8192(2× the 4096 default) and--pmode turboare the most aggressive settings in play and are plausible contributors to the timing window, but we have not isolated a single flag.- Probable code area: the v0.9.41 changelog ("fixes redundant tool schema injection in cached conversations") and v0.9.43 ("makes cached conversations more reliable by preserving complete message histories") indicate the cached-conversation / message-history subsystem was under active change around this build. A double-free /
corrupted size vs prev_size/ unaligned-tcache signature is consistent with a string/vector reallocation race in that path when multiple requests are in flight through the server's request queue while OpenMP worker threads are active.
What would help
- Whether the internal request queue (
npu_request_queue_,max_connections_insrc/server/server.hpp) fully serializes access to the conversation/KV-cache structures, or whether connection-accept / cache-reuse can run concurrently with an in-flight generation. - Whether building/running under a hardened allocator (e.g.
MALLOC_CHECK_=3, or a jemalloc/tcmalloc preload) reproduces or pinpoints the corruption site. - Any known concurrency fix landing after v0.9.43.
Reproduction (approximate)
flm serve qwen3-it:4b --pmode turbo --ctx-len 32768 --prefill-chunk-len 8192 --port 52625- Fire ~10 concurrent
/v1/chat/completionsrequests (multi-turn / with prior message history) in a tight window, repeat under sustained load. - Observe intermittent
double free or corruption/unaligned tcacheaborts on the server.
(We could not do controlled flag-isolation on our host because it has a single NPU that a live production tier is consuming — isolating would require a maintenance window or a second NPU box.)
Activity
[-]flm serve` crashes with glibc heap corruption (double free / unaligned tcache) under concurrent request bursts — Linux / XDNA2, v0.9.43[/-][+]flm serve crashes with glibc heap corruption (double free / unaligned tcache) under concurrent request bursts — Linux / XDNA2, v0.9.43[/+]jiribrachtel commentedon Jul 10, 2026
Empirical reproduction data (16-concurrent burst matrix)
We reproduced this under a controlled drain-window (single-NPU host, serve.sh-driven, 16-concurrent × 8 waves = 128 requests per config):
--pmode turbo --prefill-chunk-len 8192MALLOC_ARENA_MAX=1--pmode performance --prefill-chunk-len 4096MALLOC_ARENA_MAX=1ruled out (aggressive+arena still crashed) → not a multi-arena glibc race; corruption tracks prefill-buffer size / turbo.Probable site: the v0.9.43 KV-cache/conversation-handling redesign (token-level diff-and-splice over a retained mutable message-history buffer, plus reasoning-content isolation) — this is exactly the realloc surface a double-free / corrupted-size / unaligned-tcache points at, raced under the concurrent request queue + OpenMP threads. v0.9.44 ("Portable Linux Support") does not touch this path.
n=1 crash-run per config (one 128-req burst each) — direction consistent + mechanistically sensible, not high-n statistical.
glazperle commentedon Jul 15, 2026
Adding a Windows / XDNA2 data point and a more minimal reproduction that isolates the trigger to a single concurrent request hitting an in-flight streaming generation (not a 10-client burst). Likely the same root cause as this issue, and it matches the Windows-under-load symptom in #555.
Environment
qwen3.6-moe:35b-a3bflm serve qwen3.6-moe:35b-a3b(defaults;--preemption= 0)Minimal reproduction (2 requests, not a burst)
flm serve qwen3.6-moe:35b-a3bPOST /api/chatwith"stream": true. While A is still generating tokens…POST /api/chat(streaming or not, with or withouttools).flm serveprocess dies (exit code 5 / access violation).What isolates the trigger
stream:trueand mid-generation.stream:false) concurrent requests are safe — they queue (NPU busy, request queued (1/10)) and both complete. The crash is specific to preempting an in-flight streaming generation.toolsis not required; it also crashes with plain user messages.--preemptiondefaults to0, yet checkpoints are still created for this model and the crash still happens. Setting--preemptionexplicitly (0 or 1) does not change it.qwen3.6-moe(which checkpoints) crashes;gemma3:*(which never checkpoints) survives the identical concurrency pattern. That points at the checkpoint/restore path rather than the socket/queue layer.Why it bites in normal use
Open WebUI sends the chat as
stream:trueand concurrently fires its background Title / Tags / Follow-up task-model calls against the same model → a guaranteed second/api/chatduring streaming → reliable crash. The only thing that fully stops it today is disabling those background tasks so exactly one request reaches FLM per message.Question
Is there a
serveflag to force strict serialization (finish the active generation before admitting the next request), or to fully disable checkpoint/preemption for MoE models? If not, would it be feasible for request admission to hold a new/api/chatuntil the current streaming generation releases the NPU, instead of checkpointing mid-stream? That would make any client (Open WebUI, Frigate in #555, etc.) safe without client-side workarounds.perf: drop the 333ms NPU cooldown between queued requests
elmapache1620 commentedon Sep 20, 2026
Independent confirmation + minimal repro recipe (client-cancel path, not raw concurrency). Crashes on v1.0.5 and v1.0.6 alike.
Setup:
flm serve qwen3.6-moe:35b-a3b --host 0.0.0.0 --port 52625 --ctx-len 65000— Ubuntu 26.04.1, kernel 7.0.0-31, AMD Ryzen AI 5 340 (Strix / XDNA2), 91 GB RAM. Tested--pmode turboand--pmode performance(both crash, so power mode is not the variable).What we see. Our client (a game agent) sends one chat/completions request per action with a different prompt each time, so nearly every request is a
Prompt cache miss+Clearing context.... When the agent times out mid-generation, the disconnect lands in the cancel path:Under organic agentic load: 2 crashes per ~10 h on v1.0.5 (
double free or corruption (out)andmalloc(): unaligned tcache chunk detected).Minimal repro (NEW — sub-minute, no hours of soak)
While the server is warm, fire overlapping long-prompt POSTs where most clients disconnect mid-prefill:
Repeat 3 rounds spaced ~5 s. On v1.0.6 (released Sep 18) this aborted on round 1, in under a minute, with the identical
double free or corruption (out)afterPrefill Cancelled!→ dequeue → second disconnect.Version matrix (single machine, single config)
--pmode turbo--pmode performance--pmode performancev1.0.6's changelog contains no heap fix, and we confirm the bug is unchanged.
Suspected root cause
Race between the cancellation path and the queue consumer: on
Client disconnected; cancelling active requestthe cancelled request's buffers appear to be freed, but the dequeued-then-immediately-abandoned work still touches them (note the secondTCP connection closedarriving betweenPrompt cache missandClearing context...). TheCreating checkpoint at context length 0right beforePrefill Cancelled!suggests the cancel runs against a degenerate/zeroed context — plausibly where the corrupt free originates.Questions: Is concurrent cancel + dequeue safe at all? Does the queue assume clients never disconnect? Happy to validate an ASAN/sanitizer build against the recipe above — the repro is now deterministic, which should make this much easier to chase than our original hours-long soak.