4942ea5baf9a2b0f232b08e69fa9969fe640b925
angie
  Mon Mar 14 16:57:17 2022 -0700
Thanks Lou for a test case (mm39 rs3399875136, NM_146282.2) in which a frameshifting deletion causes a stop loss but the transcript has no 3'UTR sequence so we cannot find a new stop codon.  Instead, truncated predicted sequence led to incorrect coords from trimRefAlt and then an end < start error from indelShift.  Now, just set vpPep->cantPredict and skip the rest of the steps since we just don't have enough info.

diff --git src/hg/lib/variantProjector.c src/hg/lib/variantProjector.c
index aab92f0..df860f7 100644
--- src/hg/lib/variantProjector.c
+++ src/hg/lib/variantProjector.c
@@ -1038,54 +1038,62 @@
     else
         {
         vpPep->ref = cloneStringZ(pSeq+vpPep->start, vpPep->end - vpPep->start);
         if (endPadding > 0)
             // Copy the unchanged last base or two of ref codons
             safencpy(altCodons+altCodonsEnd, sizeof(altCodons)-altCodonsEnd,
                      txSeq->dna + cds->start + endInCds, endPadding);
         }
     char *alt = translateString(altCodons);
     if (endsWith(vpPep->ref, "X") && !endsWith(alt, "X"))
         {
         // Stop loss -- recompute alt
         freeMem(alt);
         safecpy(altCodons+altCodonsEnd, sizeof(altCodons)-altCodonsEnd, txSeq->dna + txEnd);
         alt = translateString(altCodons);
+        // But there might not be enough 3'UTR sequence to find a new stop codon...
+        if (endsWith(vpPep->ref, "X") && !endsWith(alt, "X"))
+            {
+            vpPep->cantPredict = TRUE;
+            }
         }
+    if (! vpPep->cantPredict)
+        {
         vpPep->alt = alt;
         int refLen = strlen(vpPep->ref), altLen = strlen(vpPep->alt);
         if (differentString(vpPep->ref, vpPep->alt))
             {
             // If alt has a stop codon, temporarily disguise it so it can't get trimmed
             char *altStop = strchr(vpPep->alt, 'X');
             if (altStop)
                 *altStop = 'Z';
             trimRefAlt(vpPep->ref, vpPep->alt, &vpPep->start, &vpPep->end, &refLen, &altLen);
             if (altStop)
                 *strchr(vpPep->alt, 'Z') = 'X';
             }
         if (indelShiftIsApplicable(refLen, altLen))
             {
             struct seqWindow *pSeqWin = memSeqWindowNew(vpPep->name, pSeq);
             vpPep->rightShiftedBases = indelShift(pSeqWin, &vpPep->start, &vpPep->end,
                                                   vpPep->alt, INDEL_SHIFT_NO_MAX, isdRight);
             freeMem(vpPep->ref);
             vpPep->ref = cloneStringZ(pSeq+vpPep->start, vpPep->end - vpPep->start);
             memSeqWindowFree(&pSeqWin);
             }
         dnaSeqFree((struct dnaSeq **)&txTrans);
         }
+    }
 else
     {
     vpPep->cantPredict = TRUE;
     }
 return vpPep;
 }
 
 void vpPepFree(struct vpPep **pVp)
 /* Free up a vpPep. */
 {
 if (pVp && *pVp)
     {
     struct vpPep *vp = *pVp;
     freeMem(vp->name);
     freeMem(vp->ref);