Skip to content

Deterministic SIGSEGV in sequence-checkpoint init on Metal for hybrid / SWA models (Qwen3.5, Gemma 3) #630

Description

@jb-ao

Description

AddonContextSequenceCheckpointInitWorker crashes the Node process with SIGSEGV on macOS/Metal whenever a model with needsCheckpoints === true (hybrid or sliding-window architecture) evaluates its first prompt. The crash is 100% reproducible for us across two unrelated model families and survives reboots; plain-attention models (Mistral family) never crash because the checkpoint path is never taken.

Environment

  • node-llama-cpp 3.19.0 (prebuilt Metal binary, libllama.metal.b9842.dylib)
  • macOS 26.5.1 (Darwin 25.5.0), Apple M1, 8 GB unified memory
  • Node v22.17.1
  • Models (both Q4_K_M GGUF):
    • unsloth/Qwen3.5-4B-GGUFQwen3.5-4B-Q4_K_M.gguf (hybrid attention)
    • bartowski/google_gemma-3-4b-it-GGUFgoogle_gemma-3-4b-it-Q4_K_M.gguf (sliding-window attention)

Reproduction

import { getLlama, LlamaChatSession } from 'node-llama-cpp';

const llama = await getLlama();
const model = await llama.loadModel({ modelPath: 'Qwen3.5-4B-Q4_K_M.gguf' });
const context = await model.createContext({ contextSize: 4096 });
const session = new LlamaChatSession({ contextSequence: context.getSequence() });
// Any prompt long enough for generation to start; crashes when the
// initial/interval checkpoint is taken during evaluation:
await session.promptWithMeta('<a few hundred tokens of text>', { temperature: 0.2, maxTokens: 400 });
// -> process dies with SIGSEGV, no JS error

Crashes every time (6/6 across the two models on our machine), including immediately after a clean reboot with ~0 swap in use, so it is not memory pressure.

Crash stacks (from macOS DiagnosticReports)

Qwen3.5-4B (hybrid) — KERN_INVALID_ADDRESS at 0x0000000000000250:

libllama.metal.b9842.dylib  llama_context::synchronize()
libllama.metal.b9842.dylib  llama_state_seq_get_data_ext
llama-addon.node            AddonContextSequenceCheckpointInitWorker::Execute()
llama-addon.node            Napi::AsyncWorker::OnExecute(Napi::Env)

Gemma-3-4B-it (SWA) — KERN_INVALID_ADDRESS in memmove:

libsystem_platform.dylib    _platform_memmove
libllama.metal.b9842.dylib  llama_io_write_host::~llama_io_write_host()
libllama.metal.b9842.dylib  llama_context::state_seq_get_data(int, unsigned char*, unsigned long, unsigned int)
llama-addon.node            AddonContextSequenceCheckpointInitWorker::Execute()
llama-addon.node            Napi::AsyncWorker::OnExecute(Napi::Env)

Full .ips crash reports available on request (six of them: three per model).

Analysis / notes

  • LlamaContextSequence.needsCheckpoints returns true for isHybrid || isRecurrent and for SWA models without swaFullCache — matching exactly the two families that crash. _takeCheckpoint() then constructs AddonContextSequenceCheckpoint and its init() ends up in llama_state_seq_get_data(_ext), which appears to be unsafe for these KV-cache types on Metal in the bundled llama.cpp build (possibly related to upstream issues about seq-state save/restore for hybrid/recurrent and iSWA caches).
  • Workaround that works for SWA models: createContext({ swaFullCache: true })needsCheckpoints goes false and everything runs normally (verified with a full 40-generation benchmark on the Gemma model above).
  • No workaround found for hybrid models: needsCheckpoints is unconditionally true for them, and both the initial checkpoint in LlamaChat and interval checkpoints reach the crashing init, so Qwen3.5-family models are currently unusable with 3.19.0 on Metal for us.

Thanks for the great library — happy to attach crash reports or test a patched build.

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