Undefined array key "#type" warnings break AJAX in AbstractModelFormBase::updateModelForm()
>>> [!note] Migrated issue <!-- Drupal.org comment --> <!-- Migrated from issue #3585328. --> Reported by: [mtift](https://www.drupal.org/user/751908) Related to !1519 >>> <p>[Tracker]<br> <strong>Update Summary: </strong>New bug report &mdash; one-line patch ready<br> <strong>Short Description: </strong>Undefined array key "#type" warnings break AJAX in model form<br> <strong>Check-in Date: </strong>04/23/2026<br> <em>Metadata is used by the <a href="https://www.drupalstarforge.ai/" title="AI Tracker">AI Tracker.</a> Docs and additional fields <a href="https://www.drupalstarforge.ai/ai-dashboard/docs" title="AI Issue Tracker Documentation">here</a>.</em><br> [/Tracker]</p> <h3 id="summary-problem-motivation">Problem/Motivation</h3> <p><code>AbstractModelFormBase::updateModelForm()</code> iterates every key under <code>$form['model_data']</code> and assumes each child has a <code>#type</code> key:</p> <div class="codeblock"> <pre><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br></span><span style="color: #007700">foreach (</span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'model_data'</span><span style="color: #007700">] as </span><span style="color: #0000BB">$key </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$element</span><span style="color: #007700">) {<br>&nbsp; if (</span><span style="color: #0000BB">is_array</span><span style="color: #007700">(</span><span style="color: #0000BB">$element</span><span style="color: #007700">) &amp;&amp; </span><span style="color: #0000BB">$element</span><span style="color: #007700">[</span><span style="color: #DD0000">'#type'</span><span style="color: #007700">] === </span><span style="color: #DD0000">'checkbox'</span><span style="color: #007700">) {<br>&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'model_data'</span><span style="color: #007700">][</span><span style="color: #0000BB">$key</span><span style="color: #007700">][</span><span style="color: #DD0000">'#checked'</span><span style="color: #007700">] = </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">;<br>&nbsp; }<br>}<br></span><span style="color: #0000BB">?&gt;</span></span></pre></div> <p>Render-array metadata keys (<code>#tree</code>, <code>#process</code>, etc.) are arrays without <code>#type</code>, so PHP emits <code>Undefined array key "#type"</code> warnings. Because this code runs inside an AJAX callback, the warning output is injected into the JSON response and the browser fails to parse it, producing:</p> <div class="codeblock"> <pre><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br>StatusText</span><span style="color: #007700">: </span><span style="color: #0000BB">parsererror<br>ResponseText</span><span style="color: #007700">: </span><span style="color: #0000BB">Warning</span><span style="color: #007700">:&nbsp; </span><span style="color: #0000BB">Undefined </span><span style="color: #007700">array </span><span style="color: #0000BB">key </span><span style="color: #DD0000">"#type" </span><span style="color: #0000BB">in </span><span style="color: #007700">.../</span><span style="color: #0000BB">AbstractModelFormBase</span><span style="color: #007700">.</span><span style="color: #0000BB">php on line 112<br>?&gt;</span></span></pre></div> <p>The user-visible result is a generic <em>"An AJAX HTTP error occurred. HTTP Result Code: 200"</em> dialog, with no model created.</p> <h4 id="summary-steps-reproduce">Steps to reproduce (required for bugs, but not feature requests)</h4> <p>Environment:</p> <ul> <li>Drupal core 10.x</li> <li><code>drupal/ai</code> 1.3.3</li> <li><code>ai_provider_google_vertex</code> 1.1.1</li> <li><code>key</code> module enabled with a Google service account key configured</li> <li>Browser: Firefox</li> </ul> <p>Steps:</p> <ol> <li>Navigate to <code>/admin/config/ai/providers/google_vertex</code>.</li> <li>Click <strong>Add Chat Model</strong>.</li> <li>Submit the form (or trigger any AJAX rebuild on it).</li> <li>Observe the JS error dialog and the warnings in the AJAX response payload.</li> </ol> <h3 id="summary-proposed-resolution">Proposed resolution</h3> <p>Guard the <code>#type</code> access with <code>isset()</code>:</p> <div class="codeblock"> <pre><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br></span><span style="color: #007700">foreach (</span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'model_data'</span><span style="color: #007700">] as </span><span style="color: #0000BB">$key </span><span style="color: #007700">=&gt; </span><span style="color: #0000BB">$element</span><span style="color: #007700">) {<br>&nbsp; if (</span><span style="color: #0000BB">is_array</span><span style="color: #007700">(</span><span style="color: #0000BB">$element</span><span style="color: #007700">) &amp;&amp; isset(</span><span style="color: #0000BB">$element</span><span style="color: #007700">[</span><span style="color: #DD0000">'#type'</span><span style="color: #007700">]) &amp;&amp; </span><span style="color: #0000BB">$element</span><span style="color: #007700">[</span><span style="color: #DD0000">'#type'</span><span style="color: #007700">] === </span><span style="color: #DD0000">'checkbox'</span><span style="color: #007700">) {<br>&nbsp;&nbsp;&nbsp; </span><span style="color: #0000BB">$form</span><span style="color: #007700">[</span><span style="color: #DD0000">'model_data'</span><span style="color: #007700">][</span><span style="color: #0000BB">$key</span><span style="color: #007700">][</span><span style="color: #DD0000">'#checked'</span><span style="color: #007700">] = </span><span style="color: #0000BB">FALSE</span><span style="color: #007700">;<br>&nbsp; }<br>}<br></span><span style="color: #0000BB">?&gt;</span></span></pre></div> <p>A more idiomatic fix would be to iterate <code>\Drupal\Core\Render\Element::children($form['model_data'])</code> instead, which skips render-array properties by definition. Either approach resolves the warnings.</p> <h3 id="summary-remaining-tasks">Remaining tasks</h3> <ul> <li>Decide between <code>isset()</code> guard vs. <code>Element::children()</code> iteration</li> <li>Patch + test</li> <li>Reviews</li> </ul> <h3>Related issues</h3> <ul> <li><span class="drupalorg-gitlab-issue-link project-issue-status-info project-issue-status-14"><a href="https://www.drupal.org/project/ai/issues/3584884" title="Status: Reviewed &amp; tested by the community">#3584884: Undefined array key warnings in RestrictToTopic and RegexpGuardrail buildConfigurationForm() when creating new guardrail</a></span> &mdash; same class of bug (unsafe array access in form code), different files and different fix (<code>?:</code> vs <code>??</code>). Worth a broader audit of form-handling code in the module.</li> </ul> <h3>Optional: Other details as applicable (e.g., User interface changes, API changes, Data model changes)</h3> <p>No UI, API, or data model changes. The fix is internal to one method.</p> <h3 id="summary-ai-usage">AI usage (if applicable)</h3> <p>[x] AI Assisted Issue<br><br> This issue was generated with AI assistance, but was reviewed and refined by the creator.</p> <p>[ ] AI Assisted Code<br><br> [ ] AI Generated Code<br><br> [ ] Vibe Coded</p>
issue