Undefined array key warning in ChatTranslationProvider when no language-specific prompt is configured
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3585520. --> Reported by: [mtift](https://www.drupal.org/user/751908) Related to !17 >>> <h3 id="summary-problem-motivation">Problem/Motivation</h3> <p><code>ChatTranslationProvider::translateText()</code> throws PHP warnings for every translation request when <code>ai_translate.settings.language_settings</code> has no entry for the target language, which is the default out-of-the-box state on a fresh install.</p> <pre><pre>Warning: Undefined array key "es" in src/Plugin/AiProvider/ChatTranslationProvider.php on line 187<br>Warning: Trying to access array offset on null in src/Plugin/AiProvider/ChatTranslationProvider.php on line 187</pre></pre><p>When translation runs through the batch AJAX endpoint (the normal UI flow at <code>/batch?id=&hellip;&amp;amp;op=do</code>), these warning bytes are written to the response body <em>before</em> the JSON payload. jQuery then rejects the response:</p> <blockquote><p>An AJAX HTTP error occurred.<br><br> HTTP Result Code: 200<br><br> StatusText: parsererror</p></blockquote> <p>The root cause is the unguarded array access on line 187:</p> <pre>if ($aiConfig[$targetLanguage-&amp;gt;getId()]['prompt']) {</pre><p><code>$aiConfig</code> comes from <code>ai_translate.settings.language_settings</code>, which defaults to <code>{}</code>, so the target-language key is undefined until a site admin configures a per-language prompt override. The <em>default</em> prompt fallback path immediately below (lines 195-198) works correctly; only this optional per-language branch is buggy.</p> <p>I believe this is related to, but distinct from <span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-13"><a href="https://www.drupal.org/project/ai_translate/issues/3542014" title="Status: Needs work">#3542014: Translation batch process does not handle translation errors</a></span>. That issue's MR (837) improves how caught <code>TranslationException</code>s are surfaced, but does not touch <code>ChatTranslationProvider.php</code>. These warnings fire before any exception handling runs, so !837 will not resolve the <code>parsererror</code> symptom.</p> <h4 id="summary-steps-reproduce">Steps to reproduce</h4> <ol> <li>Fresh install of <code>ai_translate</code> 1.3.1 with any chat provider configured as <code>ai.settings:default_providers.translate_text</code>. Confirmed with <code>chat_translation</code> proxy &rarr; Gemini 2.5 Flash via <code>ai_provider_google_vertex</code> 1.1.1, on Drupal 10.6.7 / PHP 8.3.</li> <li>Enable one or more non-English languages. Do <strong>not</strong> configure any entry under <em>Configuration &rarr; Regional and language &rarr; AI Translate &rarr; Language settings</em> (this is the default state).</li> <li>Edit a translatable node, go to <em>Translate</em>, and trigger "Translate with AI" for any enabled target language.</li> <li>Observe the <code>parsererror</code> dialog and the two warnings at <code>ChatTranslationProvider.php:187</code>.</li> </ol> <p>The bug can also be reproduced directly without the UI:</p> <pre><pre>drush php:eval '<br>$t&nbsp; = \Drupal::service("ai_translate.text_translator");<br>$lm = \Drupal::languageManager();<br>echo $t-&amp;gt;translateContent("Hello world.", $lm-&amp;gt;getLanguage("es"), $lm-&amp;gt;getLanguage("en"));<br>'</pre></pre><p>The translation itself succeeds, but the two warnings are emitted on stderr. In a web request context, those warnings corrupt the batch AJAX response.</p> <h3 id="summary-proposed-resolution">Proposed resolution</h3> <p>Guard the optional per-language prompt lookup. One-line change in <code>src/Plugin/AiProvider/ChatTranslationProvider.php</code>:</p> <pre><pre>-&nbsp;&nbsp;&nbsp; if ($aiConfig[$targetLanguage-&amp;gt;getId()]['prompt']) {<br>+&nbsp;&nbsp;&nbsp; if (!empty($aiConfig[$targetLanguage-&amp;gt;getId()]['prompt'])) {</pre></pre><p>I think a <code>!empty()</code> is the appropriate check here: it treats "key missing", "value is null", and "value is empty string" identically, all of which should fall through to the default-prompt path on line 195. This matches the existing style used for the default-prompt lookup immediately below (<code>if ($languageSpecificPrompt = &hellip;)</code>).</p> <p>Same patch applies cleanly to <code>1.3.x</code> and <code>2.0.x</code>. Both branches currently carry the unguarded access.</p> <h3 id="summary-remaining-tasks">Remaining tasks</h3> <ul> <li>Commit the one-line guard on <code>1.3.x</code> and <code>2.0.x</code>.</li> <li>Optional: add a lightweight unit/kernel test that calls <code>translateText()</code> with an empty <code>language_settings</code> config and asserts no PHP warnings are emitted (e.g. via <code>set_error_handler</code> or <code>expectError</code>). This would protect against future regressions in the same spot.</li> <li>Release note entry under "Bug fixes".</li> </ul> <h3 id="summary-ui-changes">User interface changes</h3> <p>None. The fix only removes the spurious warnings; the behavior when no per-language prompt is configured is unchanged. The default prompt is still used.</p> <h3 id="summary-api-changes">API changes</h3> <p>None.</p> <h3 id="summary-data-model-changes">Data model changes</h3> <p>None.</p> > Related issue: [Issue #3542014](https://www.drupal.org/node/3542014)
issue