00811fcbcfd1c9a317b07477ff46a14dba046160
braney
  Wed Sep 9 12:39:44 2026 -0700
bigBed: use the file's own field count when the type line asks for more, refs #38310

A `type bigBed N` larger than the number of fields the file holds left the
track drawing nothing at all, and its details page reporting a disagreement
instead of the item.  Fall back on the count in the file's header, which is
the count hubCheck already requires the type line to match.

The bound has to be the file's total field count and not its definedFieldCount.
Fifty-two tracks legitimately declare more bed fields than their header calls
defined, forty-eight of them the hs1 T2T_Encode_LOPeaks narrowPeak set, and
those are untouched.

Three tracks are in the over-declared state today, all `type bigBed 4` over a
three-field file: hg38 setDups, and the KAPA_HyperExome and
nexterarapidcapture subtracks of hg19 exomeProbesets.  Their item boxes render
pixel-identically and their details pages, which failed before, now work.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

diff --git src/hg/hgc/bigBedClick.c src/hg/hgc/bigBedClick.c
index 0eb19d930e3..45dd8e7b564 100644
--- src/hg/hgc/bigBedClick.c
+++ src/hg/hgc/bigBedClick.c
@@ -431,30 +431,35 @@
     // item is an insertion; expand the search range from 0 bases to 2 so we catch it:
     ivStart = max(0, start-1);
     ivEnd++;
     }
 char *quickLiftFile = cloneString(trackDbSetting(tdb, "quickLiftUrl"));
 struct hash *chainHash = NULL;
 struct bigBedInterval *bbList = NULL;
 if (quickLiftFile)
     bbList = quickLiftGetIntervals(quickLiftFile, bbi, chrom, ivStart, ivEnd, &chainHash);
 else
     bbList = bigBedIntervalQuery(bbi, chrom, ivStart, ivEnd, 0, lm);
 
 /* Get bedSize if it's not already defined. */
 if (bedSize == 0)
     bedSize = bbi->definedFieldCount;
+else if (bedSize > bbi->fieldCount)
+    /* The type line asks for more fields than the file holds.  Use the file's own count,
+     * the same fallback hgTracks makes, so the item that was drawn is the item described
+     * here. */
+    bedSize = bbi->fieldCount;
 
 /* A bigBed always has at least chrom, chromStart and chromEnd.  A smaller count
  * can only come from a bad type line, and the bedSize - 3 below would then run
  * off the front of restFields[]. */
 if (bedSize < 3)
     errAbort("Track %s declares 'type bigBed %d', but a bigBed has at least 3 fields.",
              tdb->track, bedSize);
 
 char *scoreFilter = cartOrTdbString(cart, tdb, "scoreFilter", NULL);
 int minScore = 0;
 if (scoreFilter)
     minScore = atoi(scoreFilter);
 
 /* Find particular item in list - matching start, and item if possible. */
 boolean found = FALSE;