64675c24b3136d06f2123a1039a034114bd597b6
lrnassar
  Thu Feb 12 13:35:41 2026 -0800
Improving error messages mostly on hubCheck, with a few trackHub.c cases. Overall making the messages more informative to tell users what went wrong and what they can do to fix it, refs #35718

diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c
index 0df9264a79b..846159a0f7f 100644
--- src/hg/lib/trackHub.c
+++ src/hg/lib/trackHub.c
@@ -877,32 +877,32 @@
     next = el->next;
     if (el->twoBitPath != NULL)
 	deleteAssembly(el->name, el, hub);
     trackHubGenomeFree(&el);
     }
 hub->genomeList = NULL;
 }
 
 static char *requiredSetting(struct trackHub *hub, struct trackHubGenome *genome,
 	struct trackDb *tdb, char *setting)
 /* Fetch setting or give an error message, a little more specific than the
  * error message from trackDbRequiredSetting(). */
 {
 char *val = trackDbSetting(tdb, setting);
 if (val == NULL)
-    errAbort("Missing required '%s' setting in hub %s genome %s track %s", setting,
-    	hub->url, genome->name, tdb->track);
+    errAbort("Missing required '%s' setting in hub %s genome %s track %s. Add a '%s' line to the track stanza.", setting,
+    	hub->url, genome->name, tdb->track, setting);
 return val;
 }
 
 static void forbidSetting(struct trackHub *hub, struct trackHubGenome *genome,
     struct trackDb *tdb, char *setting)
 /* Abort if forbidden setting found. */
 {
 if (trackDbSetting(tdb, setting))
     errAbort("Forbidden setting '%s' in hub %s genome %s track %s", setting,
         hub->url, genome->name, tdb->track);
 }
 
 static void expandOneUrl(struct hash *settingsHash, char *hubUrl, char *variable)
 {
 struct hashEl *hel = hashLookup(settingsHash, variable);
@@ -1435,54 +1435,57 @@
     /* RMH: Added support for bigRmsk track hub data type */
     else if (startsWithWord("bigNarrowPeak", type) || startsWithWord("bigBed", type) ||
                 startsWithWord("bigGenePred", type)  || startsWithWord("bigPsl", type)||
                 startsWithWord("bigChain", type)|| startsWithWord("bigMaf", type) ||
                 startsWithWord("bigBarChart", type) || startsWithWord("bigInteract", type) ||
                 startsWithWord("bigLolly", type) || startsWithWord("bigRmsk",type))
         {
         /* Just open and close to verify file exists and is correct type. */
         struct bbiFile *bbi = bigBedFileOpen(bigDataUrl);
         char *typeString = cloneString(type);
         nextWord(&typeString);
         if (startsWithWord("bigBed", type) && (typeString != NULL))
             {
             unsigned numFields = sqlUnsigned(nextWord(&typeString));
             if (numFields > bbi->fieldCount)
-                errAbort("fewer fields in bigBed (%d) than in type statement (%d) for track %s with bigDataUrl %s", bbi->fieldCount, numFields, trackHubSkipHubName(tdb->track), bigDataUrl);
+                errAbort("bigBed file '%s' has %d fields, but track \"%s\" declares 'type bigBed %d'. Either regenerate the bigBed with the correct number of fields, or change the type line to 'type bigBed %d' to match the file.", bigDataUrl, bbi->fieldCount, trackHubSkipHubName(tdb->track), numFields, bbi->fieldCount);
             }
         bbiFileClose(&bbi);
         }
     else if (startsWithWord("vcfTabix", type) || startsWithWord("vcfPhasedTrio", type))
         {
         /* Just open and close to verify file exists and is correct type. */
         struct vcfFile *vcf = vcfTabixFileAndIndexMayOpen(bigDataUrl, bigDataIndex, NULL, 0, 0, 1, 1);
         if (vcf == NULL)
             // Warnings already indicated whether the tabix file is missing etc.
-            errAbort("Couldn't open %s and/or its tabix index (.tbi) file.  "
-                     "See http://genome.ucsc.edu/goldenPath/help/vcf.html",
-                     bigDataUrl);
+            errAbort("Couldn't open %s and/or its tabix index (.tbi) file for track %s. "
+                     "Both the .vcf.gz file and a matching .vcf.gz.tbi index must be publicly accessible "
+                     "at the same URL path. Generate the index with: tabix -p vcf yourFile.vcf.gz",
+                     bigDataUrl, trackHubSkipHubName(tdb->track));
         vcfFileFree(&vcf);
         }
     else if (startsWithWord("bam", type))
         {
         bamFileAndIndexMustExist(bigDataUrl, bigDataIndex);
         }
     else if (startsWithWord("longTabix", type))
         {
         struct bedTabixFile *btf = bedTabixFileMayOpen(bigDataUrl, NULL, 0, 0);
         if (btf == NULL)
-            errAbort("Couldn't open %s and/or its tabix index (.tbi) file.", bigDataUrl);
+            errAbort("Couldn't open %s and/or its tabix index (.tbi) file for track %s. "
+                     "Both the file and a matching .tbi index must be publicly accessible "
+                     "at the same URL path.", bigDataUrl, trackHubSkipHubName(tdb->track));
         bedTabixFileClose(&btf);
         }
 #ifdef USE_HAL
     else if (startsWithWord("halSnake", type))
         {
         char *errString;
         int handle = halOpenLOD(bigDataUrl, &errString);
         if (handle < 0)
             errAbort("HAL open error: %s", errString);
         if (halClose(handle, &errString) < 0)
             errAbort("HAL close error: %s", errString);
         }
 #endif
     else if (startsWithWord("hic", type))
         {