@@ -148,6 +148,12 @@ def get_validation_species_from_watchlist(
148148
149149 species_list = []
150150 genome_paths = []
151+ # Track entries whose Kraken2 taxid fell back to the raw NCBI taxid
152+ # because nothing mapped them. On a GTDB/custom-taxid database (where the
153+ # NCBI taxid is absent), read extraction by that taxid yields ZERO reads
154+ # and validation silently produces nothing -- the failure mode found
155+ # auditing a custom-taxid DB. We surface it as a warning below.
156+ unmapped_names = []
151157
152158 for entry in entries :
153159 ncbi_taxid = getattr (entry , 'taxid' , 0 )
@@ -159,9 +165,11 @@ def get_validation_species_from_watchlist(
159165 # so the operator does not have to run "Scan Database"; otherwise
160166 # fall back to the auto-mapping collection, then to the NCBI taxid.
161167 kraken_taxid = ncbi_taxid # Default to NCBI taxid
168+ mapped = False
162169 explicit_db_taxid = getattr (entry , 'db_taxid' , None )
163170 if explicit_db_taxid :
164171 kraken_taxid = explicit_db_taxid
172+ mapped = True
165173 logging .debug (
166174 f"Using explicit db_taxid { explicit_db_taxid } for "
167175 f"{ getattr (entry , 'name' , '' )} "
@@ -170,10 +178,14 @@ def get_validation_species_from_watchlist(
170178 db_taxid = mapping_collection .get_db_taxid (ncbi_taxid )
171179 if db_taxid :
172180 kraken_taxid = db_taxid
181+ mapped = True
173182 logging .debug (
174183 f"Mapped NCBI { ncbi_taxid } -> Kraken2 { db_taxid } for { getattr (entry , 'name' , '' )} "
175184 )
176185
186+ if not mapped :
187+ unmapped_names .append (getattr (entry , 'name' , '' ) or str (ncbi_taxid ))
188+
177189 species_info = {
178190 'taxid' : ncbi_taxid ,
179191 'kraken_taxid' : kraken_taxid ,
@@ -190,6 +202,31 @@ def get_validation_species_from_watchlist(
190202 f"Found { len (species_list )} enabled watchlist species, "
191203 f"{ len (genome_paths )} with downloaded genomes"
192204 )
205+
206+ # Warn loudly when validation taxids fell back to raw NCBI taxids: on a
207+ # custom/GTDB database this silently extracts 0 reads. Distinguish "never
208+ # scanned" (no mapping at all) from "scanned but these did not map".
209+ if unmapped_names :
210+ preview = ", " .join (unmapped_names [:5 ]) + (
211+ f" (+{ len (unmapped_names ) - 5 } more)" if len (unmapped_names ) > 5 else "" )
212+ if mapping_collection is None :
213+ logging .warning (
214+ "No Kraken2 taxid mapping has been generated for this database, "
215+ "so validation will use raw NCBI taxids (%d species: %s). If this "
216+ "is a GTDB or custom database whose taxids differ from NCBI, read "
217+ "extraction will find ZERO reads and validation will produce "
218+ "nothing. Run 'Scan Database' / 'Verify Taxonomy IDs' in the "
219+ "Watchlist & Preparation tab before starting." ,
220+ len (unmapped_names ), preview ,
221+ )
222+ else :
223+ logging .warning (
224+ "%d watchlist species could not be mapped to this Kraken2 "
225+ "database (%s); validation will fall back to their NCBI taxids "
226+ "and may find no reads if the database does not contain them." ,
227+ len (unmapped_names ), preview ,
228+ )
229+
193230 return species_list , genome_paths
194231
195232 except (ImportError , AttributeError ) as e :
0 commit comments