Skip to content

Fix TypeError in LanguageDropdown when used in multiple mode#5823

Open
akolson wants to merge 1 commit intolearningequality:hotfixesfrom
akolson:fix-native_name-conundrum
Open

Fix TypeError in LanguageDropdown when used in multiple mode#5823
akolson wants to merge 1 commit intolearningequality:hotfixesfrom
akolson:fix-native_name-conundrum

Conversation

@akolson
Copy link
Copy Markdown
Member

@akolson akolson commented Apr 13, 2026

Summary

LanguageDropdown is used with multiple prop in SearchFilters.vue. In that mode, v-model holds an Array of selected language IDs. VAutocomplete's updateAutocomplete passes this.internalValue (the Array) to getValue, which eagerly evaluates getText(internalValue) as a JS argument before calling getPropertyFromItem — even though that fallback is never actually needed. getText in turn calls languageText(array). Arrays are objects in JS, so the primitive short-circuit guard in getPropertyFromItem does not apply, and languageText is invoked with the array directly. Since arrays have no native_name, item.native_name.split throws a TypeError.

Fix: guard languageText against item being null/undefined or lacking a native_name property (covers arrays, partial objects, and any future edge cases) by returning an empty string early.

Verification: ran the existing languageDropdown test suite and confirmed all tests pass, including two new cases covering the missing-native_name and array-input scenarios.

References

Fixes #5740
Recurrence of the issue addressed by #5465 (the null check was subsequently reverted without a documented reason).

Reviewer guidance

  • LanguageDropdown.vue:120 — the new guard uses == null (not !item.native_name) deliberately, to avoid catching empty-string native_name values that the existing test exercises.
  • SearchFilters.vue:68-71 — this is where multiple is used; reproduce the crash by opening Import from Channels, selecting a language filter, then blurring the dropdown.
  • No risky areas: change is purely defensive, touches only languageText in the dropdown component.

AI usage

I used Claude Code to trace through the Vuetify VAutocomplete and VSelect source to identify why languageText was receiving an Array argument in multiple mode. After understanding the root cause (eager argument evaluation in getValue), I wrote the guard and two new test cases. I reviewed the generated code and confirmed the condition == null is correct for the intended behaviour.

VAutocomplete eagerly evaluates getText(internalValue) as the fallback
argument to getValue, even when the fallback is never used. In multiple
mode (used in SearchFilters), internalValue is an Array of selected ids.
Arrays are objects in JS, so getPropertyFromItem does not short-circuit
on the primitive guard and calls languageText with the array directly.
Since arrays have no native_name property, this throws a TypeError.

Guard languageText against item being null/undefined or lacking a
native_name (covers arrays, partial objects, and any future edge cases).

Fixes learningequality#5740.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@akolson akolson requested a review from rtibblesbot April 13, 2026 12:26
Copy link
Copy Markdown
Contributor

@rtibblesbot rtibblesbot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tight, well-reasoned hotfix for the Sentry crash — guard and tests are exactly right.

CI passing. Phase 3: no dev server available; the template is entirely unchanged (only the languageText method was modified), so there is nothing visual to verify — the fix's correctness is established by the new unit tests and CI.

  • praise: see inline (×2)

@rtibblesbot's comments are generated by an LLM, and should be evaluated accordingly

How was this generated?

Reviewed the pull request diff checking for:

  • Correctness: bugs, edge cases, undocumented behavior, resource leaks, hardcoded values
  • Design: unnecessary complexity, naming, readability, comment accuracy, redundant state
  • Architecture: duplicated concerns, minimal interfaces, composition over inheritance
  • Testing: behavior-based assertions, mocks only at hard boundaries, accurate coverage
  • Completeness: missing dependencies, unupdated usages, i18n, accessibility, security
  • Principles: DRY (same reason to change), SRP, Rule of Three (no premature abstraction)
  • Checked CI status and linked issue acceptance criteria
  • For UI changes: inspected screenshots for layout, visual completeness, and consistency

},
methods: {
languageText(item) {
// VAutocomplete eagerly evaluates getText(internalValue) as a fallback arg to
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: The comment explaining Vuetify's eager getText(internalValue) argument evaluation is exactly the right thing to document here — this is non-obvious framework internals and would otherwise pull future maintainers into a VAutocomplete/VSelect source dive to understand why the guard exists.

// getValue, even when that fallback isn't needed. In multiple mode, internalValue
// is an Array, and arrays have no native_name. Guard against both that case and
// any other scenario where item or native_name is missing.
if (!item || item.native_name == null) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: == null (rather than !item.native_name) is the precisely correct check. It catches null, undefined, and array inputs (where .native_name is undefined) while deliberately allowing native_name: '' through so existing behaviour for empty-string entries is preserved. The companion test at line 82 of the spec explicitly pins this distinction — good defensive coding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants