08be525807ff3b3caf1233b9af15b010b950052b
hiram
  Wed Sep 16 16:53:43 2026 -0700
gracefully manage bad response from api search requests refs #38365

diff --git src/hg/js/liftRequest.js src/hg/js/liftRequest.js
index 061afc2e442..4da49bd3b9a 100644
--- src/hg/js/liftRequest.js
+++ src/hg/js/liftRequest.js
@@ -63,31 +63,36 @@
     } else {
         liftPath = "https://hgdownload.soe.ucsc.edu/goldenPath/";
         liftPath += asm1;
     }
     liftPath += "/liftOver/" + asm1 + "To";
     liftPath += asm2.charAt(0).toUpperCase() + asm2.slice(1);
     liftPath += ".over.chain.gz";
     return(liftPath);
 }
 
 function checkAssemblyCompatibility(asm1, asm2) {
     const url = "/cgi-bin/hubApi/liftOver/listExisting?fromGenome=" + encodeURIComponent(asm1) +
                 ";" + "toGenome=" + encodeURIComponent(asm2);
 
     fetch(url)
-      .then(response => response.json())
+      .then(response => {
+        if (!response.ok) {
+            throw new Error("listExisting request failed: " + response.status);
+        }
+        return response.json();
+      })
       .then(response => {
 //      console.log(JSON.stringify(response, null, 2));
         if (response.itemsReturned >= 1) {
           const liftPath1 = liftOverPath(asm1, asm2);
           const liftPath2 = liftOverPath(asm2, asm1);
           const browser1 = "/cgi-bin/hgTracks?db=" + asm1;
           const browser2 = "/cgi-bin/hgTracks?db=" + asm2;
 
           fileExists(liftPath1, function(exists) {
             if (exists) {
               document.getElementById("genome1Link").href = browser1;
               document.getElementById("genome1Link").textContent = assembly1Value;
 
               document.getElementById("genome1LiftOver").href = liftPath1;
               document.getElementById("genome1LiftOver").textContent = asm1 + " to " + asm2;
@@ -385,31 +390,37 @@
         showError("Error", errorMsg);
       });
 }	// end of function submitForm()
 
 function dismissLiftExists() {
     resetFormVisibility();
     document.getElementById("genomeSearch1").value = "";
     document.getElementById("genomeSearch2").value = "";
     assembly1Value = "";
     assembly2Value = "";
     genome1 = "";
     genome2 = "";
 }
 
 function onSearchError(jqXHR, textStatus, errorThrown, term) {
-    return [{label: 'No genomes found', value: '', genome: '', disabled: true}];
+    // This callback only fires when the search request itself failed
+    // (network error, non-2xx status, bad response) -- not for a
+    // legitimate zero-match result -- so say so rather than implying
+    // there were no matching genomes.
+    console.error("Genome search failed:", textStatus, errorThrown);
+    return [{label: 'Genome search is temporarily unavailable, please try again shortly',
+             value: '', genome: '', disabled: true}];
 }
 
 document.addEventListener("DOMContentLoaded", () => {
     // Assembly 1 autocomplete
     let selectEle1 = document.getElementById("genomeLabel1");
     let boundSelect1 = assembly1Select.bind(null, selectEle1);
     initSpeciesAutoCompleteDropdown('genomeSearch1', boundSelect1,
         "/cgi-bin/hubApi/findGenome?browser=mustExist;q=", null, null, onSearchError);
 
     let btn1 = document.getElementById("genomeSearchButton1");
     btn1.addEventListener("click", () => {
         let val = document.getElementById("genomeSearch1").value;
         $("[id='genomeSearch1']").autocompleteCat("search", val);
     });