SubtitleEdit/subtitleedit · error · HttpRequestException

No usable translation in {Name} reply{Error}

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.

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)

Solutions

  1. Verify the LlamaCpp server's chat template matches the model (use --chat-template or the correct .gguf with baked-in template).
  2. Try a larger or instruction-tuned model that follows the translation prompt format.
  3. Check the Error property value (appended to the message) for parser diagnostics.
  4. Reduce the batch size setting so each request sends fewer lines, reducing parsing complexity.
  5. Inspect the raw model output by enabling debug/verbose logging in the LlamaCppAdvancedProtocol to see what the server actually returned.
  6. 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

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


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/0754b038a02b48ac. Report an issue: GitHub.