mudler/LocalAI · critical
[acestep-cpp] FATAL: failed to load BPE tokenizer\n
Error message
[acestep-cpp] FATAL: failed to load BPE tokenizer\n
What it means
acestep-cpp fatal during generation setup: load_bpe_from_gguf() on the text-encoder GGUF failed, so prompts cannot be tokenized; generate_music returns 3. It means the text-encoder file is missing/unreadable, not a GGUF, or lacks the tokenizer (vocab/merges) metadata this loader expects.
Source
Thrown at backend/go/acestep-cpp/cpp/goacestepcpp.cpp:166
// Compute T (latent frames at 25Hz)
int T = (int)(duration * FRAMES_PER_SECOND);
T = ((T + g_dit.cfg.patch_size - 1) / g_dit.cfg.patch_size) * g_dit.cfg.patch_size;
int S = T / g_dit.cfg.patch_size;
if (T > 15000) {
fprintf(stderr, "[acestep-cpp] ERROR: T=%d exceeds max 15000\n", T);
return 2;
}
int Oc = g_dit.cfg.out_channels; // 64
int ctx_ch = g_dit.cfg.in_channels - Oc; // 128
fprintf(stderr, "[acestep-cpp] T=%d, S=%d, duration=%.1fs, seed=%d\n", T, S, duration, seed);
// 1. Load BPE tokenizer from text encoder GGUF
BPETokenizer tok;
if (!load_bpe_from_gguf(&tok, g_text_enc_path.c_str())) {
fprintf(stderr, "[acestep-cpp] FATAL: failed to load BPE tokenizer\n");
return 3;
}
// 2. Build formatted prompts (matches dit-vae.cpp text2music template)
std::string instruction = "Fill the audio semantic mask based on the given conditions:";
char metas[512];
snprintf(metas, sizeof(metas),
"- bpm: %s\n- timesignature: %s\n- keyscale: %s\n- duration: %d seconds\n",
bpm_str, ts_str.c_str(), ks_str.c_str(), (int)duration);
std::string text_str = std::string("# Instruction\n") + instruction + "\n\n" +
"# Caption\n" + cap_str + "\n\n" +
"# Metas\n" + metas + "<|endoftext|>\n";
std::string lyric_str = std::string("# Languages\n") + lang_str + "\n\n# Lyric\n" +
lyrics_str + "<|endoftext|>";
// 3. TokenizeView on GitHub (pinned to 44413a9d06)
Solutions
- Verify g_text_enc_path exists and is the text-encoder GGUF from the same matched artifact set as the DiT.
- Inspect it for tokenizer keys (gguf-dump | grep -i 'tokenizer\|vocab\|merge') and re-download/re-convert with the documented converter if absent.
- Check load_model stored the intended path — argument order matters (lm, text_encoder, dit, vae).
Example fix
# before: tokenizer tensors missing gguf-dump text_enc.gguf | grep -c tokenizer # 0 -> FATAL at generate # after: re-export with converter that embeds BPE gguf-dump text_enc.gguf | grep -c tokenizer # >0 -> tokenizes ok
Defensive patterns
Strategy: validation
Validate before calling
# verify tokenizer tensors exist in the text-encoder GGUF before deploy
gguf-dump text_enc.gguf | grep -qi 'tokenizer' || { echo 'text_enc.gguf lacks BPE data' >&2; exit 1; }
[ -f "$TEXT_ENC" ] || { echo 'text encoder missing' >&2; exit 1; } Type guard
bool text_encoder_has_bpe(const char *path) {
BPETokenizer tok;
bool ok = load_bpe_from_gguf(&tok, path);
if (ok) bpe_tokenizer_free(&tok);
return ok;
} Prevention
- Ship the text-encoder GGUF as part of the matched artifact set; never deploy DiT+VAE alone.
- Use the documented converter revision so vocab/merges are embedded in the GGUF.
- Return code 3 from generate_music specifically means tokenizer stage — check the text-encoder path first.
When it happens
Trigger: load_model succeeded for DiT/VAE but generate_music is called with g_text_enc_path pointing at a missing file, a non-GGUF, or a text-encoder GGUF converted without embedded BPE vocab/merges; load_bpe_from_gguf returns false.
Common situations: Text-encoder artifact forgotten in deployment (only DiT+VAE copied); community conversions stripping tokenizer tensors; path typos for the second of four model paths; mismatched converter revision.
Related errors
- [acestep-cpp] FATAL: failed to load DiT from %s\n
- [acestep-cpp] FATAL: silence_latent not found in %s\n
- [acestep-cpp] FATAL: cannot read GGUF metadata from %s\n
- [acestep-cpp] ERROR: models not loaded\n
- [acestep-cpp] ERROR: T=%d exceeds max 15000\n
AI-assisted analysis of mudler/LocalAI@44413a9d06 (2026-08-15).
Data as JSON: /api/errors/dc03bbff1d1ce8af.
Report an issue: GitHub.