ClinVar 2026-07: 951 records inside our regions changed classification since 2026-05. What changed
Sample report Support Log in
aimostı Check your file

Under the hood

Lifting a genome from GRCh37 to GRCh38: what CrossMap quietly changes

Many whole-genome files are still delivered on GRCh37, and translating them to GRCh38 is the usual first step. On a real gVCF, CrossMap removed the deletion from about one variant record in eight and left the genotype pointing at an allele that was no longer there. This is the mechanism, and the guard we built around it.

Two versions of the human reference genome are in common use. GRCh37 was released in 2009 and GRCh38 in 2013. They number most of the genome differently, and at many thousands of positions they disagree about the reference base itself, because GRCh38 corrected it. A liftover tool uses a chain file to translate each record in a variant file from one assembly to the other. CrossMap is one of the most widely used, and on most records it is right. The failures described here are narrow, but they change genotypes instead of dropping records, and a pipeline does not notice a genotype that changed.

The deletion that was classified as an insertion

CrossMap decides whether a VCF record is a substitution, an insertion or a deletion by comparing the length of the REF column with the length of the ALT column. It measures the whole ALT column, commas included. In a gVCF every variant record carries an extra symbolic allele, <NON_REF>, so a two-base deletion AT to A arrives with ALT written as A,<NON_REF>. That is eleven characters against a REF of two, and the record is classified as an insertion.

For an insertion CrossMap keeps a single reference base, here A. It then removes any ALT allele equal to the reference. The deletion allele is A, so it is removed. The record survives as A to <NON_REF>, and its genotype column, which pointed at allele 1, the deletion, now points at <NON_REF>.

On a real GRCh37 gVCF from a DRAGEN pipeline, 13.3 percent of variant records had this shape. On a plain indel VCF from the same kind of pipeline it was 4.8 percent. In one slice we checked record by record, all 1,863 affected records were multi-allelic deletions. We run CrossMap 0.7.3; the same two lines are still in 0.7.4, released in July 2026.

The reference base that changed

At positions where GRCh38 corrected the reference base, CrossMap writes the GRCh38 base into REF and deletes any ALT allele equal to it. It does not renumber the genotype or the per-allele fields. If the person carries the GRCh38 base, which is usually the common one at a corrected site, the per-allele depth and likelihood lists no longer match the alleles, a two-allele record can be left with an empty ALT, and the genotype indices point at the wrong alleles.

On one real 3.9 GB GRCh37 gVCF this touched 803,947 of about 121.8 million variant records, or 0.66 percent. On a plain SNV file, every one of 899 dropped records was a site where the person carried the corrected base.

The guard

Once CrossMap has rewritten a record, the allele it removed is gone and cannot be recovered. The repair has to be set up before the lift. We split every multi-allelic record into two-allele records with bcftools norm, trim each to its shortest form, and write its allele count and REF length into the INFO field, which CrossMap passes through untouched. The trimming matters: an untrimmed CTTTCT to CTTTCTTTCT lifts as C to CTTTCTTTCT, a different allele with its count still intact.

After the lift, any record whose allele count or REF length changed is dropped, and the drop is counted as an unread position. Then a gate: if more than 3 percent of variant records were dropped, the file is refused. That threshold is measured, not chosen. Healthy gVCFs drop between 0.14 and 0.66 percent and plain SNV files between 0.9 and 1.5 percent, while a file lifted with the wrong chain drops 25 percent or more.

One more thing turned up only on a whole genome. Where a chain block maps to the reverse strand, CrossMap writes records in reverse order, so the lifted file cannot be indexed until it is sorted. Small test files hid this, because the normaliser's small reorder buffer absorbed it.

If you lift VCFs yourself

Split multi-allelic records before the lift. Record each record's allele count and compare it afterwards. Measure your drop rate on a real whole-genome file, because every defect above passed on small test files. And look at BCFtools/liftover, published in 2024, which swaps alleles at a corrected reference base instead of dropping them. We have not switched to it yet, because it needs the GRCh37 reference sequence on our servers and we have not measured it on our files.

What Aimosti would (and wouldn't) show you

A GRCh37 genome is lifted to GRCh38 before anything in it is read. Records that the guard drops are treated as unread, so they show up as gaps in what the report examined, never as a genotype. If a file loses more than the healthy share of its records in the lift, we refuse it rather than report on what is left.

What we won't claim

We won't report a genotype from a record whose alleles changed during the lift, and we won't call a GRCh37 file fully read when the lift dropped part of it. CrossMap is a useful tool and we still run it; this is about two specific mechanisms, measured on real files.

Bottom line. A liftover can change a genotype without failing. Count each record's alleles before and after the lift, and treat any record whose alleles changed as unread.

Related: Whole-genome report (GRCh37 files). Restated from: CrossMap source code (GitHub) · CrossMap on PyPI (release history) · Genovese et al., BCFtools/liftover, Bioinformatics 2024 · The VCF 4.2 specification · Genome Reference Consortium: human assemblies.

This is the kind of answer we give. See what your file says.

See a sample report Get your report · €39