Skip to content

mlx_lm.server speculative decoding fails on Qwen 35B target: ArraysCache is not trimmable #1446

Description

@toolkode

Summary

mlx_lm.server speculative decoding fails for a Qwen 35B target model with a Qwen 0.8B draft model because the prompt cache is ArraysCache, which speculative_generate_step rejects as non-trimmable.

This reproduces in both a normal draft speed smoke and a no-explicit-prompt-cache probe. Baseline generation without --draft-model works.

Related context: #872 tracks internal MTP support for Qwen/Nemotron models; this issue is specifically about external draft-model speculative decoding failing at runtime because the selected cache is not trimmable.

Environment

  • macOS 26.0, arm64
  • Python 3.12.11
  • mlx-lm==0.31.3
  • mlx==0.31.2
  • Runtime: mlx_lm.server

Models

Target model:

  • Path: /Volumes/Models-toolkode/models/Qwen3.6-35B-A3B-UD-MLX-4bit
  • Architecture: Qwen3_5MoeForConditionalGeneration
  • Model type: qwen3_5_moe
  • 4-bit affine quantization

Draft model:

  • Path: /Volumes/Models-toolkode/models/Qwen3.5-0.8B-8bit
  • Architecture: Qwen3_5ForConditionalGeneration
  • Model type: qwen3_5
  • 8-bit affine quantization

Repro

/Users/aaron/Code/training-llm/.venv-mlx/bin/mlx_lm.server \
  --model /Volumes/Models-toolkode/models/Qwen3.6-35B-A3B-UD-MLX-4bit \
  --draft-model /Volumes/Models-toolkode/models/Qwen3.5-0.8B-8bit \
  --num-draft-tokens 5 \
  --host 127.0.0.1 \
  --port 18087 \
  --log-level ERROR

GET /v1/models succeeds. A chat completion request then fails during generation with:

ValueError: Speculative decoding requires a trimmable prompt cache (got {'ArraysCache'}).

Trace tail:

File ".../mlx_lm/generate.py", line 716, in stream_generate
  for n, (token, logprobs, from_draft) in enumerate(token_generator):
File ".../mlx_lm/generate.py", line 531, in speculative_generate_step
  raise ValueError(
ValueError: Speculative decoding requires a trimmable prompt cache (got {'ArraysCache'}).

Expected

Speculative decoding should either:

  • use/select a trimmable cache for this path,
  • support trimming the cache type used by these Qwen hybrid-attention models, or
  • fail during server startup / first validation with a clear unsupported-configuration error before accepting requests.

Actual

The server accepts startup/model requests, then the completion handler crashes during speculative generation because ArraysCache is not accepted as trimmable.

Notes

This was found while benchmarking local ToolKode worker inference. Prefix-cache-only baseline works and the same target model without --draft-model generated normally at about 44 tok/s in our speed smoke.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions