571aecdf42c832e61ee921e977589ca386467d13
max
  Fri Sep 4 12:24:17 2026 -0700
hubCheck: report a bigDataUrl that cannot be opened instead of dropping the track, refs #38260

hubCheckGenome() called trackDbPolishAfterLinkup(), whose pruneEmpties() step hands
each track to addTrackIfDataAccessible(), which frees any track whose data cannot be
reached. That is right for the browser, which should degrade gracefully rather than
draw a broken track, and wrong for hubCheck, whose main job is to say that the file
is unreachable. The track was gone before the file check ran, so hubCheck printed
nothing and exited 0:

cd hubCheck/tests/input
sed 's|test6field.bb|noSuchFile.bb|' fieldCountMismatch.txt > tmp.txt
hubCheck tmp.txt      # only the descriptionUrl warning, missing file not mentioned

Split the non-pruning part of trackDbPolishAfterLinkup() into
trackDbPolishAfterLinkupKeepAll() and call that from hubCheck. Every other caller
still goes through trackDbPolishAfterLinkup() and still prunes, so browser behaviour
is unchanged.

Added a tests/ case whose bigDataUrl does not exist. Before this change it produced
no output and exit 0; now it reports "Couldn't open input/relPath/data/noSuchFile.bb".

Of the existing tests, only badType changes, and it gains a real error that the prune
had been hiding: 'unrecognized type "wig" for track "invalidType"'. badType was
already failing before this commit and still is, for an unrelated reason: seven tests
carry expected output with per-track "missing description page" warnings that no
longer appear, because those hubs point at remote URLs that no longer resolve and
hubCheckTrack aborts at the file check before reaching the description check. That is
stale test data, not addressed here.

diff --git src/hg/lib/hdb.c src/hg/lib/hdb.c
index 61c17b9f7ce..f7bff6c42fc 100644
--- src/hg/lib/hdb.c
+++ src/hg/lib/hdb.c
@@ -4374,42 +4374,50 @@
 struct trackDb *tdb;
 
 /* Insert a little paranoid check here to make sure this doesn't get called twice. */
 for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
     if (tdb->children !=  NULL)
         internalErr();
 
 for (tdb = tdbList; tdb != NULL; tdb = tdb->next)
     {
     struct trackDb *parent = tdb->parent;
     if (parent != NULL)
         refAdd(&parent->children, tdb);
     }
 }
 
-struct trackDb *trackDbPolishAfterLinkup(struct trackDb *tdbList, char *db)
-/* Do various massaging that can only be done after parent/child
- * relationships are established. */
+struct trackDb *trackDbPolishAfterLinkupKeepAll(struct trackDb *tdbList)
+/* The part of trackDbPolishAfterLinkup that every caller wants, without dropping
+ * tracks whose data cannot be reached.  hubCheck needs this: a track pruned because
+ * its bigDataUrl does not resolve is exactly the track hubCheck has to report on. */
 {
-tdbList = pruneEmpties(tdbList, db, hIsPrivateHost() || hIsPreviewHost(), 0);
 addChildRefsToParents(tdbList);
 trackDbContainerMarkup(NULL, tdbList);
 rInheritFields(tdbList);
 slSort(&tdbList, trackDbCmp);
 return tdbList;
 }
 
+struct trackDb *trackDbPolishAfterLinkup(struct trackDb *tdbList, char *db)
+/* Do various massaging that can only be done after parent/child
+ * relationships are established. */
+{
+tdbList = pruneEmpties(tdbList, db, hIsPrivateHost() || hIsPreviewHost(), 0);
+return trackDbPolishAfterLinkupKeepAll(tdbList);
+}
+
 struct trackDb *hTrackDbWithCartVersion(char *db, int *retCartVersion)
 /* Load tracks associated with current db.
  * Supertracks are loaded as a trackDb, but are not in the returned list,
  * but are accessible via the parent pointers of the member tracks.  Also,
  * the supertrack trackDb subtrack fields are not set here (would be
  * incompatible with the returned list)
  * Returns list sorted by priority
  *	NOTE: this result is cached, do not free it !
  */
 {
 if (trackHubDatabase(db))
     return NULL;
 
 if (isHubTrack(db))
     {