# Diagnose Bioconductor annotation failures: org.db ID mapping and TxDb genome-build mismatches

Use this when `select()` / `mapIds()` on an `org.*.db` package returns all NAs,
throws keytype errors, or gives 1:many mappings you did not expect — or when
coordinates from a `TxDb` package disagree with your data (silently empty
overlaps, gene positions that look wrong). Annotation failures split into
identifier-mapping failures and genome-build failures; classify which you have
before remapping anything.

## 1. Failure class A: org.db ID mapping errors and NA floods

The org.db interface is `AnnotationDbi`: `select()`, `mapIds()`, `keytypes()`,
`columns()`, `keys()`. The package name encodes the organism and the key type —
`org.Hs.eg.db` means human, Entrez Gene central keys ('eg' = Entrez Gene).

**Step 1 — read the exact error.**

`unable to find an inherited method for function 'mapIds' for signature
'"character"'` means the first argument was a character string, not the
database object. A frequent cause: storing the package name in a variable.

```r
library(AnnotationDbi)
library(org.Hs.eg.db)

# WRONG: org_pkg is a string; mapIds has no method for character
org_pkg <- "org.Hs.eg.db"
mapIds(org_pkg, ids, "ENTREZID", "ENSEMBL")

# RIGHT: pass the loaded database object
org_pkg <- org.Hs.eg.db
mapIds(org_pkg, ids, "ENTREZID", "ENSEMBL")
```

`None of the keys entered are valid keys for 'X'. Please use the keys method to
see a listing of valid arguments.` means the `keytype` does not match the
identifier flavor you passed. Discover what the package actually offers:

```r
keytypes(org.Hs.eg.db)   # identifier flavors accepted as keytype
columns(org.Hs.eg.db)    # columns you may request
head(keys(org.Hs.eg.db, keytype = "ENSEMBL"))  # what keys look like
```

Typical mistake: passing Ensembl IDs (`ENSG...`) with `keytype = "ENTREZID"`
or gene symbols with `keytype = "ENSEMBL"`.

**Step 2 — if there is no error but most results are NA: check the data
vintage.** org.db packages are rebuilt from the current NCBI/Ensembl snapshot
at each Bioconductor release, and the package version tracks the release
(e.g. `org.Hs.eg.db_3.12.0` shipped with Bioconductor 3.12). IDs retired or
renamed since your IDs were generated — versioned Ensembl IDs with the
`.11` suffix that changed, withdrawn symbols, merged Entrez records — return
NA because they no longer exist in the snapshot:

```r
packageVersion("org.Hs.eg.db")   # which snapshot you are mapping against
sum(is.na(symbols))              # how many keys failed to map
```

Fixes: strip Ensembl version suffixes (`sub("[.].*$", "", ids)`) if the
snapshot predates them, match the org.db vintage to the vintage that produced
the IDs, and accept that a small NA fraction is normal (withdrawn records),
not a bug in your code.

**Step 3 — duplicate mappings are expected; choose the resolution.** Gene
identifiers are often 1:many. `select()` returns all rows; `mapIds()` requires
`keytype` and takes a single `column`, resolving duplicates via `multiVals`
(default `"first"`). Alternatives: `"list"`, `"CharacterList"`, `"filter"`,
`"asNA"`, or a user-supplied function:

```r
mapIds(org.Hs.eg.db, ids, "SYMBOL", "ENSEMBL", multiVals = "list")
```

If a script "worked" on an old org.db and now returns different symbols, the
vintage changed, not the code — pin the package version.

## 2. Failure class B: TxDb genome-build and chromosome-name skew

TxDb package names encode the source and the genome build, e.g.
`TxDb.Hsapiens.UCSC.hg19.knownGene` (UCSC, hg19, knownGene track). The
current-build counterpart follows the same scheme with `hg38`. Two independent
things must agree with your data: the build and the chromosome naming.

**Step 1 — confirm the build.** The coordinates in a TxDb are only valid for
its build:

```r
library(TxDb.Hsapiens.UCSC.hg38.knownGene)
txdb <- TxDb.Hsapiens.UCSC.hg38.knownGene
genome(txdb)     # e.g. "hg38" -- must match the reference your reads were aligned to
```

If the alignments used hg38 and the TxDb is hg19, overlaps and gene
coordinates are silently wrong — nothing errors, the numbers just disagree.
There is no automatic fix; install the TxDb for the build that matches the
data.

**Step 2 — confirm the chromosome-name style.** `findOverlaps()` matches the
triplet (seqname, range, strand), so `chr1` in your data vs `1` in the TxDb
yields zero hits with no warning. Check and convert with GenomeInfoDb:

```r
library(GenomeInfoDb)
seqlevelsStyle(txdb)          # e.g. "UCSC" (chr1) vs "NCBI" (1)
seqlevelsStyle(txdb) <- "NCBI"  # renames chr1 -> 1, chrM -> MT, etc.
```

Do the conversion on one side so both sides share a style, then re-run the
overlap. To drop unplaced scaffolds and alt contigs before comparing:

```r
txdb <- keepStandardChromosomes(txdb, pruning.mode = "coarse")
```

**Step 3 — sanity-check the overlap result, not just the code.** After
alignment of build and style, spot-check with `countOverlaps()` or
`subsetByOverlaps()` on a known gene (e.g. pull `transcripts(txdb)` for a
housekeeping gene and confirm your reads overlap it). Zero overlaps after the
build/style check points back to the counting stage, not the annotation.

## 3. Failure class C: AnnotationHub / ExperimentHub cache errors

Packages that fetch hub resources at load time can fail with:

```
error: Invalid Cache: sqlite file
Hub has not been added to cache
Run again with 'localHub=FALSE'
```

The local hub cache was never initialized or is corrupt. Initialize it first,
answering "yes" if prompted to create the local cache directory, then
re-install or re-load the package:

```r
AnnotationHub::AnnotationHub()      # or ExperimentHub::ExperimentHub()
```

The AnnotationHub vignette "Troubleshooting the Cache" documents the recovery
steps for the persistent cases.

## 4. Checklist for the failing annotation step

1. Classify: A (ID mapping: error or NA flood), B (TxDb coordinates: silent
   wrong/empty results), C (hub cache error at load).
2. A-error: pass the db object, not the package-name string, to `mapIds`;
   discover valid flavors with `keytypes()`/`columns()`/`keys()`.
3. A-NA: compare `packageVersion("org.Hs.eg.db")` against the vintage that
   produced the IDs; strip version suffixes; resolve 1:many with `multiVals`.
4. B: `genome(txdb)` must equal the alignment build; `seqlevelsStyle()` must
   match on both sides — convert one side, then re-run overlaps;
   `keepStandardChromosomes(..., pruning.mode = "coarse")` to drop alt contigs.
5. C: initialize the hub with `AnnotationHub()` / `ExperimentHub()` before
   installing or loading.
