{"record":{"id":"a9183d4f2d677474","repo":"SubtitleEdit/subtitleedit","slug":"staticname-returned-an-unexpected-response-res","errorCode":null,"errorMessage":"{StaticName} returned an unexpected response: {responseString}","messagePattern":"(.+?) returned an unexpected response: (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"src/libuilogic/AutoTranslate/NoLanguageLeftBehindApi.cs","lineNumber":67,"sourceCode":"        {\n            return new NoLanguageLeftBehindServe().GetSupportedTargetLanguages();\n        }\n\n        public async Task<string> Translate(string text, string sourceLanguageCode, string targetLanguageCode, CancellationToken cancellationToken)\n        {\n            var content = new StringContent(\"{ \\\"text\\\": \\\"\" + Json.EncodeJsonText(text) + \"\\\",  \\\"source\\\": \\\"\" + sourceLanguageCode + \"\\\", \\\"target\\\": \\\"\" + targetLanguageCode + \"\\\" }\", Encoding.UTF8, \"application/json\");\n            using var result = await _httpClient.PostAsync(\"translator\", content, cancellationToken);\n            result.EnsureSuccessStatusCode();\n\n            var responseString = await result.Content.ReadAsStringAsync(cancellationToken);\n\n            var parser = new SeJsonParser();\n            var resultText = parser.GetFirstObject(responseString, \"result\");\n            if (resultText == null)\n            {\n                Error = responseString;\n                SeLogger.Error($\"{GetType().Name} got unexpected JSON: {responseString}\");\n                throw new Exception($\"{StaticName} returned an unexpected response: {responseString}\");\n            }\n\n            return Json.DecodeJsonText(resultText);\n        }\n\n        public void Dispose() => _httpClient?.Dispose();\n    }\n}\n","sourceCodeStart":49,"sourceCodeEnd":76,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/libuilogic/AutoTranslate/NoLanguageLeftBehindApi.cs#L49-L76","documentation":"Thrown by NoLanguageLeftBehindApi when the self-hosted NLLB service returns a 2xx response (EnsureSuccessStatusCode passed) but the JSON has no top-level 'result' field that the parser can extract. Indicates the service responded successfully but with an unexpected/empty schema, or the wrong service is at the configured URL.","triggerScenarios":"Translate() posts {text, source, target} to <base>/translator; result.EnsureSuccessStatusCode() passes; SeJsonParser.GetFirstObject(responseString, \"result\") returns null. Happens when the URL points to a different NLLB variant (e.g. nllb-serve vs winstxnhdw-nllb-api which returns {\"result\": ...}), or when the service returns an error-shaped 200 like {\"error\": ...}.","commonSituations":"AutoTranslateNllbApiUrl pointing at a different NLLB implementation whose response key is not 'result'; service returning {\"translatedText\": ...} or an error object with HTTP 200; missing trailing slash on the URL (the code appends one at Initialize to avoid a .NET base-address 404, but a wrong path still misroutes).","solutions":["Confirm AutoTranslateNllbApiUrl points at the winstxnhdw/nllb-api implementation (returns {\"result\": ...}).","Log/capture responseString to see the actual body and find the right key.","Ensure the URL has a trailing slash (the code adds one, but verify the stored value).","If using a different NLLB fork, switch to the matching translator class (e.g. NoLanguageLeftBehindServe)."],"exampleFix":"// before\nvar resultText = parser.GetFirstObject(responseString, \"result\");\nif (resultText == null)\n{\n    Error = responseString;\n    SeLogger.Error($\"{GetType().Name} got unexpected JSON: {responseString}\");\n    throw new Exception($\"{StaticName} returned an unexpected response: {responseString}\");\n}\n\n// after - try common alternative keys before giving up, and hint at a mismatched service\nvar resultText = parser.GetFirstObject(responseString, \"result\")\n    ?? parser.GetFirstObject(responseString, \"translatedText\")\n    ?? parser.GetFirstObject(responseString, \"translation\");\nif (resultText == null)\n{\n    Error = responseString;\n    SeLogger.Error($\"{GetType().Name} got unexpected JSON (expected a 'result' key). URL: {_httpClient.BaseAddress}. Body: {responseString}\");\n    throw new Exception($\"{StaticName} returned an unexpected response (no 'result' key - is this the winstxnhdw/nllb-api service?): {responseString}\");\n}","handlingStrategy":"validation","validationCode":"// Validate the NLLB URL and probe the service shape before translating\nvar url = Configuration.Settings.Tools.AutoTranslateNllbApiUrl;\nif (string.IsNullOrWhiteSpace(url))\n    throw new InvalidOperationException(\"NLLB API URL is not set.\");\nusing var c = new HttpClient { Timeout = TimeSpan.FromSeconds(5) };\nvar body = \"{\\\"text\\\":\\\"hi\\\",\\\"source\\\":\\\"eng_Latn\\\",\\\"target\\\":\\\"spa_Latn\\\"}\";\nvar resp = await c.PostAsync(url.TrimEnd('/') + \"/translator\", new StringContent(body, Encoding.UTF8, \"application/json\"));\nvar json = await resp.Content.ReadAsStringAsync();\nif (!json.Contains(\"\\\"result\\\"\"))\n    throw new InvalidOperationException($\"NLLB service at {url} did not return a 'result' key - is this winstxnhdw/nllb-api? Body: {json}\");","typeGuard":"public static bool ResponseHasResultKey(string body) => body.Contains(\"\\\"result\\\"\");","tryCatchPattern":"try\n{\n    return await nllb.Translate(text, src, tgt, token);\n}\ncatch (Exception ex) when (ex.Message.Contains(\"unexpected response\"))\n{\n    throw new InvalidOperationException(\"NLLB returned a 2xx with no 'result' key - check the URL points at winstxnhdw/nllb-api and the schema matches.\", ex);\n}","preventionTips":["Ensure the URL points at the winstxnhdw/nllb-api fork (returns {\"result\": ...}).","Keep a trailing slash on the base URL (the code adds one, but verify).","Probe the service with a tiny request on setup to confirm the response shape.","If using a different NLLB variant, use the matching translator class."],"tags":["self-hosted","parsing","schema","translation","nllb","configuration"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}