tools/mtmd · libmtmd audio tokenization
Contribution roleParticipating investigator — not the primary owner; no implementation submitted
Investigating a recoverable boundary for one-sample audio
A provisional, non-primary investigation of an audio boundary in libmtmd: a structurally valid one-sample PCM bitmap can reach a process-level assertion, turning a malformed request into a server availability failure.
- Issue
- #27693
- Pull request
- Not opened
- Module
- tools/mtmd · libmtmd audio tokenization
System context
llama.cpp is a cross-platform C/C++ inference project with model loading, local/server inference, CPU and GPU backends, and multimodal inputs. The issue is in libmtmd, the layer that prepares media before it enters a model; it is not in a backend kernel or text generation loop.
For audio, llama-server accepts an OpenAI-compatible input_audio file, mtmd_helper decodes WAV/MP3/FLAC through miniaudio into mono F32 PCM, and libmtmd creates an audio bitmap. mtmd_tokenize then selects a model-specific preprocessor and turns the media into multimodal chunks and audio tokens.
Audio input is experimental and the shared tokenizer can select several preprocessors. That matters because a shared boundary check must not silently expand the accepted input domain for every audio-capable model just because one model may pad a very short signal.
Trigger and impact
The issue report describes a 16 kHz mono WAV with exactly one decoded sample on the Voxtral path. One mono F32 sample is a legitimate four-byte buffer: nx == 1, buf.size() == sizeof(float), and the buffer remains correctly aligned.
The current tokenizer treats nx == 0 as a recoverable empty-input error, but a later check requires buf.size() > sizeof(float). For one sample, 4 > 4 is false, so GGML_ASSERT reaches ggml_abort rather than returning a request error.
The reported CLI exits and the reported server loses /health after one request. Those runtime results are reported upstream, not reproduced locally: my contribution currently confirms the static path and the remaining acceptance gates, not a Windows reproduction or a fix.
Root cause
The underlying bitmap is not corrupt. Its byte size is nx * sizeof(float), so a one-sample object satisfies the representation and alignment invariants. The fault is that a user-controlled minimum-length question was expressed as an internal, process-terminating memory assertion.
Simply changing > to >= would stop this specific assertion, but it would also send a one-sample signal into every model-specific preprocessor. Whisper-style processing may pad it; Conformer, Parakeet, Granite Speech, Qwen3 TTS, and other paths have different frame, normalisation, or minimum-length semantics. Static evidence does not justify globally accepting it.
The error boundary also has to account for placeholder bitmaps used by /input_tokens. A fix based only on the real buffer could make token-count and normal completion paths disagree for the same sample count.
Fix and boundary
No source change has been made. The provisional direction is to reject nx < 2 at the shared audio-tokenization boundary with the existing LOG_ERR + return-error contract, before real-buffer and placeholder paths split. That would turn the abnormal input into a recoverable request failure instead of allowing it to reach an abort.
The existing alignment assertion would remain an internal invariant. Normal nx >= 2 audio would still enter exactly the same preprocessor path, while the patch would avoid defining one-sample numerical behaviour across every audio model.
This is a design candidate, not an implementation claim. Before any code, it needs a baseline reproduction, an explicit choice about zero-sample error wording, real-buffer and placeholder checks, and a regression test that fails before the change and passes afterward.
Why this boundary
This record is intentionally marked as a non-primary contribution. The primary contribution candidate moved to Issue #27697; #27693 remains a documented investigation and planning contribution, not a claimed ownership of the bug or its future patch.
I did not collapse the proposal into a one-character >= change because the shared boundary serves multiple preprocessors with different semantics. The safer scope is to make a bad external request recoverable without asserting a new, unverified minimum-audio policy for all models.
The page preserves the distinction between reported behaviour, static source evidence, and open runtime gates. There is no implementation, local commit, PR, CI result, maintainer review, or merge to claim at this stage.
Verification
- 01
As of 27 Aug 2026 11:40 AEST, the upstream Issue was open and labelled bug-unconfirmed, with no linked Development branch or PR. The reported macOS abort remains a source report, not a locally reproduced result.
- 02
Static source review at local baseline 11cd988 confirms the reachable path: decoded mono F32 PCM becomes an audio bitmap; nx == 1 produces four bytes; tools/mtmd/mtmd.cpp still uses the strict > sizeof(float) assertion after the recoverable nx == 0 branch.
- 03
No fetch, build, model run, code edit, regression test, commit, push, PR, or CI run has been performed for this record. Windows baseline reproduction, server survival checks, placeholder coverage, and the full 0/1/2/normal-audio matrix remain open gates.
Upstream progress
- Static source path
Confirmed at local baseline 11cd988
- Local reproduction
Not run
- Implementation and regression
Candidate design only
- Pull request
Not created