Summary
Environment:
Mac: M3 Max (48 GB), macOS Sequoia 15
mlx-audio 0.4.4
mlx 0.31.2
Model: mlx-community/Kokoro-82M-bf16 (also tested Unravler/Kokoro-82M-4bit-MLX)
Wrapper: kokoro-tts-mlx 0.1.0 (github.com/flight505/kokoro_tts_mlx)
Python 3.12
Symptoms:
All audio output is NaN + zeros — no actual audio content
np.isnan() shows ~20-25% of samples are NaN, rest are 0.0
Affects ALL language codes (a, b, e, etc.) and ALL voices
The same model (hexgrad/Kokoro-82M) via PyTorch kokoro.KPipeline works perfectly (zero NaN, real audio)
Root cause — two bugs:
NaN output via kokoro-tts-mlx wrapper: KokoroTTS.generate() returns arrays where np.isnan() is true for ~20% of samples and the rest are silent zeros
Shape broadcast crash via native mlx-audio / generate_audio(): intermittent ValueError: [broadcast_shapes] Shapes (1,N,1) and (1,N+300,9) cannot be broadcast in istftnet.py:620 — the F0 sine generator produces misaligned tensor shapes
Key clue: The shape error always shows a delta of exactly 300 samples between the two dimensions (72000 vs 72300, 1200000 vs 1200300), suggesting a frame-size rounding bug in the MLX port of the Kokoro decoder (istftnet.py).
Workaround: PyTorch kokoro.KPipeline(lang_code='e', repo_id='hexgrad/Kokoro-82M') works perfectly on CPU at ~11× realtime on M3 Max.
Steps to reproduce
"""Minimal reproducer: MLX Kokoro NaN + shape crash bugs."""
import numpy as np
import json
from pathlib import Path
from huggingface_hub import hf_hub_download
from mlx_audio.tts.models.kokoro import KokoroPipeline, ModelConfig, Model
import dacite
MODEL = "mlx-community/Kokoro-82M-bf16"
config = dacite.from_dict(
ModelConfig,
json.loads(Path(hf_hub_download(MODEL, "config.json")).read_text()),
)
model = Model(config, repo_id=MODEL)
── Bug 1: NaN output (all languages) ──
for code, label, voice in [("a", "English", "af_heart"), ("e", "Spanish", "ef_dora")]:
pipe = KokoroPipeline(lang_code=code, model=model, repo_id=MODEL)
for r in pipe("Hello." if code == "a" else "Hola.", voice=voice):
a = np.array(r.audio)
print(f"{label}: NaN={np.isnan(a).sum()}/{a.shape[-1]} mean_abs={np.abs(a).mean():.4f} min={a.min():.4f} max={a.max():.4f}")
break
del pipe
── Bug 2: broadcast shape crash on longer text ──
pipe = KokoroPipeline(lang_code="e", model=model, repo_id=MODEL)
try:
for r in pipe("Hola, esto es una prueba un poco mas larga.", voice="ef_dora"):
print(f"Bug 2: no crash, shape={np.array(r.audio).shape}")
break
except ValueError as e:
print(f"Bug 2: CRASH — {e}")
Expected behavior
pipeline:
import numpy as np
from kokoro import KPipeline
pipeline = KPipeline(lang_code='e', repo_id='hexgrad/Kokoro-82M')
for r in pipeline('Hola, esto es una prueba.', voice='ef_dora'):
a = r.audio.numpy()
print(f"NaN: {np.isnan(a).sum()}")
print(f"mean_abs: {np.abs(a).mean():.4f}")
print(f"min/max: {a.min():.4f} / {a.max():.4f}")
print(f"shape: {a.shape}")
break
expected output:
NaN: 0
mean_abs: 0.0271
min/max: -0.4099 / 0.3390
shape: (72000,)
Actual behavior
10MB files with noaudio in them
Package version
flight505/kokoro_tts_mlx
macOS version and chip
26.5.2 (25F84) on Apple M3 Max
Python and MLX versions
Python: 3.12 mlx: 0.31.2 mlx-audio: 0.4.4
Additional context
And the model variants tried:
mlx-community/Kokoro-82M-bf16 (327 MB, bf16)
Unravler/Kokoro-82M-4bit-MLX (4-bit quantized) — same bug on both
Summary
Environment:
Mac: M3 Max (48 GB), macOS Sequoia 15
mlx-audio 0.4.4
mlx 0.31.2
Model: mlx-community/Kokoro-82M-bf16 (also tested Unravler/Kokoro-82M-4bit-MLX)
Wrapper: kokoro-tts-mlx 0.1.0 (github.com/flight505/kokoro_tts_mlx)
Python 3.12
Symptoms:
All audio output is NaN + zeros — no actual audio content
np.isnan() shows ~20-25% of samples are NaN, rest are 0.0
Affects ALL language codes (a, b, e, etc.) and ALL voices
The same model (hexgrad/Kokoro-82M) via PyTorch kokoro.KPipeline works perfectly (zero NaN, real audio)
Root cause — two bugs:
NaN output via kokoro-tts-mlx wrapper: KokoroTTS.generate() returns arrays where np.isnan() is true for ~20% of samples and the rest are silent zeros
Shape broadcast crash via native mlx-audio / generate_audio(): intermittent ValueError: [broadcast_shapes] Shapes (1,N,1) and (1,N+300,9) cannot be broadcast in istftnet.py:620 — the F0 sine generator produces misaligned tensor shapes
Key clue: The shape error always shows a delta of exactly 300 samples between the two dimensions (72000 vs 72300, 1200000 vs 1200300), suggesting a frame-size rounding bug in the MLX port of the Kokoro decoder (istftnet.py).
Workaround: PyTorch kokoro.KPipeline(lang_code='e', repo_id='hexgrad/Kokoro-82M') works perfectly on CPU at ~11× realtime on M3 Max.
Steps to reproduce
"""Minimal reproducer: MLX Kokoro NaN + shape crash bugs."""
import numpy as np
import json
from pathlib import Path
from huggingface_hub import hf_hub_download
from mlx_audio.tts.models.kokoro import KokoroPipeline, ModelConfig, Model
import dacite
MODEL = "mlx-community/Kokoro-82M-bf16"
config = dacite.from_dict(
ModelConfig,
json.loads(Path(hf_hub_download(MODEL, "config.json")).read_text()),
)
model = Model(config, repo_id=MODEL)
── Bug 1: NaN output (all languages) ──
for code, label, voice in [("a", "English", "af_heart"), ("e", "Spanish", "ef_dora")]:
pipe = KokoroPipeline(lang_code=code, model=model, repo_id=MODEL)
for r in pipe("Hello." if code == "a" else "Hola.", voice=voice):
a = np.array(r.audio)
print(f"{label}: NaN={np.isnan(a).sum()}/{a.shape[-1]} mean_abs={np.abs(a).mean():.4f} min={a.min():.4f} max={a.max():.4f}")
break
del pipe
── Bug 2: broadcast shape crash on longer text ──
pipe = KokoroPipeline(lang_code="e", model=model, repo_id=MODEL)
try:
for r in pipe("Hola, esto es una prueba un poco mas larga.", voice="ef_dora"):
print(f"Bug 2: no crash, shape={np.array(r.audio).shape}")
break
except ValueError as e:
print(f"Bug 2: CRASH — {e}")
Expected behavior
pipeline:
import numpy as np
from kokoro import KPipeline
pipeline = KPipeline(lang_code='e', repo_id='hexgrad/Kokoro-82M')
for r in pipeline('Hola, esto es una prueba.', voice='ef_dora'):
a = r.audio.numpy()
print(f"NaN: {np.isnan(a).sum()}")
print(f"mean_abs: {np.abs(a).mean():.4f}")
print(f"min/max: {a.min():.4f} / {a.max():.4f}")
print(f"shape: {a.shape}")
break
expected output:
NaN: 0
mean_abs: 0.0271
min/max: -0.4099 / 0.3390
shape: (72000,)
Actual behavior
10MB files with noaudio in them
Package version
flight505/kokoro_tts_mlx
macOS version and chip
26.5.2 (25F84) on Apple M3 Max
Python and MLX versions
Python: 3.12 mlx: 0.31.2 mlx-audio: 0.4.4
Additional context
And the model variants tried:
mlx-community/Kokoro-82M-bf16 (327 MB, bf16)
Unravler/Kokoro-82M-4bit-MLX (4-bit quantized) — same bug on both