SubtitleEdit/subtitleedit · error · HttpRequestException
No usable translation in
Error message
No usable translation in {Name} reply{Error} What it means
Thrown by AdvancedTranslatorBase when a LlamaCpp-based translation engine returns zero usable translations from a batch, even after the code recursively halves the batch size down to 1 line. When count <= 1 and still no translation is produced, the method gives up and throws an HttpRequestException with the engine name and any error detail accumulated in the Error property.
Solutions
- Verify the LlamaCpp server's chat template matches the model (use --chat-template or the correct .gguf with baked-in template).
- Try a larger or instruction-tuned model that follows the translation prompt format.
- Check the Error property value (appended to the message) for parser diagnostics.
- Reduce the batch size setting so each request sends fewer lines, reducing parsing complexity.
- Inspect the raw model output by enabling debug/verbose logging in the LlamaCppAdvancedProtocol to see what the server actually returned.
- Ensure the source and target language codes passed are English language names (as the code comment notes ListLanguages puts the name in Code).
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify the LlamaCpp server is reachable and responding before translation
var healthResp = await _httpClient.GetAsync(GetApiUrl() + "/health", cancellationToken);
if (!healthResp.IsSuccessStatusCode)
throw new InvalidOperationException("LlamaCpp server is not responding at " + GetApiUrl()); Try / catch
try { return await TranslateChunkAsync(rows, index, count, src, tgt, ct); }
catch (HttpRequestException ex) when (ex.Message.Contains("No usable translation"))
{ /* log Error property, skip batch, fall back to single-line translation or different model */ } Prevention
- Test the LlamaCpp model with a simple single-line translation before batch processing.
- Verify the model's chat template is correctly configured on the server.
- Use a model size and quantization level appropriate for translation tasks (7B+ instruct models).
- Keep batch sizes small to isolate which lines cause parse failures.
When it happens
Trigger: TranslateChunkAsync is called with a batch; the model's response yields 0 parsed translations. The code retries with count/2 (halving). If count was already 1 (or the recursive call also gets 0), the throw fires. This happens when the LlamaCpp server returns a response the parser cannot extract any translation from.
Common situations: The LlamaCpp model is too small or undertrained and outputs garbage/unparseable text; the system prompt format doesn't match the model's expected chat template; the context window is exceeded and the model truncates its output; the model echoes the prompt instead of translating; a quantization artefact causes repetitive empty output; the LlamaCpp server is misconfigured (wrong chat format, no instruct template).
Related errors
- Translation engine returned no translation for line after…
- No llama.cpp translate model found in
- Ollama returned
- Translate engine ' ' is not supported. Use one of: .
- Translate model file not found
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/0754b038a02b48ac.
Report an issue: GitHub.
Appendix: source
Thrown at src/ui/Features/Translate/LlamaCppAdvanced/AdvancedTranslatorBase.cs:110
{
for (var i = 0; i < count; i++)
{
var translation = map[i + 1];
rows[index + i].TranslatedText = translation.Length > 0 ? translation : rows[index + i].Text;
}
});
return count;
}
if (count > 1)
{
// The model could not fill the full batch - translate the first half only; the outer
// loop calls again for the rest (with the successful half now part of the history).
return await TranslateChunkAsync(rows, index, count / 2, sourceLanguageCode, targetLanguageCode, cancellationToken);
}
throw new HttpRequestException("No usable translation in " + Name + " reply" +
(string.IsNullOrEmpty(Error) ? string.Empty : ": " + Error));
}
private async Task<Dictionary<int, string>> TranslateLinesAsync(List<LlamaCppAdvancedProtocol.BatchLine> lines, List<LlamaCppAdvancedProtocol.HistoryPair> history, string sourceLanguageCode, string targetLanguageCode, CancellationToken cancellationToken)
{
var client = _client ?? throw new InvalidOperationException("Initialize() not called");
var settings = Se.Settings.AutoTranslate.LlamaCppAdvanced;
var url = GetApiUrl();
// The "codes" this engine receives are English language names (ListLanguages puts the
// name in TranslationPair.Code), which is what the prompt expects.
var systemPrompt = LlamaCppAdvancedProtocol.BuildSystemPrompt(sourceLanguageCode, targetLanguageCode, settings);
var userContent = LlamaCppAdvancedProtocol.BuildUserContent(history, lines);
var responseFormat = LlamaCppAdvancedProtocol.BuildResponseFormatJson(lines);
var map = new Dictionary<int, string>();
for (var attempt = 0; attempt < 2 && !cancellationToken.IsCancellationRequested; attempt++)
{View on GitHub (pinned to 17a9f07487)