@@ -549,6 +549,26 @@ public List<Integer> getQualificationStartYears() {
549549 return qualificationStartYears ;
550550 }
551551
552+ /**
553+ * Validates that the parallel lists (qualifications, curriculums, qualificationStartYears) have matching sizes.
554+ * Logs a warning if they don't match.
555+ *
556+ * @return true if lists are valid (same size or all null/empty), false if mismatched
557+ */
558+ public boolean validateListSizes () {
559+ int qualCount = (qualifications == null ) ? 0 : qualifications .size ();
560+ int currCount = (curriculums == null ) ? 0 : curriculums .size ();
561+ int yearCount = (qualificationStartYears == null ) ? 0 : qualificationStartYears .size ();
562+
563+ if (qualCount != currCount || qualCount != yearCount ) {
564+ LOGGER .warn ("Academy '{}' has mismatched list sizes: qualifications={}, curriculums={}, startYears={}. "
565+ + "This may cause errors when viewing course tooltips." ,
566+ name , qualCount , currCount , yearCount );
567+ return false ;
568+ }
569+ return true ;
570+ }
571+
552572 /**
553573 * Retrieves the base skill level granted by this academy.
554574 *
@@ -812,6 +832,13 @@ public String getTooltip(Campaign campaign, List<Person> personnel, int courseIn
812832 MekHQ .getMHQOptions ().getLocale ());
813833
814834 try {
835+ // Bounds check: ensure courseIndex is valid for curriculums list
836+ if (curriculums == null || courseIndex < 0 || courseIndex >= curriculums .size ()) {
837+ LOGGER .error ("Invalid courseIndex {} for academy '{}' with {} curriculums" ,
838+ courseIndex , name , curriculums == null ? 0 : curriculums .size ());
839+ return "<html><body style='width: 200px'><i>Error: Invalid course data</i></body></html>" ;
840+ }
841+
815842 StringBuilder tooltip = new StringBuilder ().append ("<html><body style='width: 200px'>" );
816843 tooltip .append ("<i>" ).append (description ).append ("</i><br><br>" );
817844 tooltip .append ("<b>" ).append (resources .getString ("curriculum.text" )).append ("</b><br>" );
0 commit comments