BED File Coordinate Error: Causes and Fixes
By Dr. Zubair Khalid, DVM, MS, PhD ·

A BED file coordinate error usually comes from one specific mistake: a start position copied from a 1-based file such as GFF, GTF, VCF, or SAM without subtracting 1. The first thing to check is column two of your BED file against the annotation or alignment file it was built from. If every feature in the file is shifted by exactly one base, you have found the problem in under a minute.
Everything else follows from that single design decision. BED counts from zero and stops before the last base, while nearly every other genomics format counts from one and includes the last base. The two conventions describe the same biology, but they produce different numbers for the same feature. When those numbers leak across a tool boundary, you get intervals that look plausible, pass file-format validation, and still produce wrong overlaps, wrong sequences, and wrong counts.
This guide works through the causes of BED coordinate error from the most common to the rarest, explains the mechanism behind each one, and gives the commands that confirm and repair it. It also covers the file-format context that makes the errors possible, including how FASTQ and FASTA files interact with coordinate systems, and it ends with prevention practices that stop the problem from recurring.
What a BED Coordinate Really Means
BED is a tab-delimited text format for genomic intervals, originally defined by the UCSC Genome Browser team and documented in the UCSC format FAQ. The standard has twelve columns, and a file may carry as few as three.
| Column | Field | Meaning | Notes |
|---|---|---|---|
| 1 | chrom | Chromosome or scaffold name | Must match the reference exactly |
| 2 | chromStart | 0-based start | First base of the feature is numbered 0 |
| 3 | chromEnd | End position, exclusive | The base at chromEnd is not in the feature |
| 4 | name | Feature label | Free text, no spaces |
| 5 | score | 0 to 1000 | Integer, per the UCSC specification |
| 6 | strand | +, -, or . | Single character |
| 7 | thickStart | Start of the thick drawn region | Often the CDS start |
| 8 | thickEnd | End of the thick drawn region | Often the CDS end |
| 9 | itemRgb | RGB color | Three integers 0 to 255 |
| 10 | blockCount | Number of blocks | Must match columns 11 and 12 |
| 11 | blockSizes | Comma-terminated lengths | Relative to chromStart |
| 12 | blockStarts | Comma-terminated offsets | Relative to chromStart |
A file with three columns is called BED3. Six columns make BED6, and the full twelve make BED12. The distinction matters because some tools silently accept BED3 where they need BED6, and others reject BED12 where they expect a flat interval.
The 0-based, half-open contract
BED uses a half-open interval. If a feature occupies bases 101 through 200 of a chromosome in one-based counting, the BED record is chr1 100 200. The start was decremented, the end was left alone, and the length is 200 - 100 = 100. That arithmetic is the whole system.
The half-open design is deliberate. It makes interval arithmetic clean. Two adjacent features that share a boundary produce 100 200 and 200 300, with no overlap and no gap. Inclusive systems make that same adjacency awkward, since the first feature ends at 200 and the second begins at 201. For a track viewer that draws thousands of features, the half-open convention removes a class of edge-case bugs.
It also removes your margin for error. Every conversion in and out of BED is a place where the subtraction can be applied twice, not at all, or to the wrong column.
How GFF, GTF, VCF, and SAM count
The Sequence Ontology GFF3 specification and the Ensembl GFF/GTF documentation both define start and end as 1-based and inclusive. A GFF3 exon line reading chr1 source exon 101 200 . + . ID=exon1 covers bases 101 through 200, and the length is 200 - 101 + 1 = 100. Note the plus one. That term is the entire difference between the two systems.
VCF uses a 1-based POS column that names the leftmost base of the REF allele. A single-nucleotide variant at POS 100 occupies exactly one base, and its BED representation is chr1 99 100. An insertion or deletion occupies length(REF) bases starting at POS, so the BED end is POS - 1 + length(REF).
SAM and BAM also use 1-based coordinates for the POS field, while the CIGAR string describes alignment operations. The SAM specification caps reference length at 2^29 - 1, which is 536,870,911 bases. That cap is far beyond any current assembly, but it explains why BAM-derived features on very long concatenated references can fail in ways that look like coordinate errors.
GFF also orders its columns differently from BED. Column three in GFF is the feature type, a word such as exon or gene. Column three in BED is chromEnd, a number. A quick test for a mislabeled file is to check whether the third column is numeric.
FASTA, FASTQ, and the reference that defines the coordinates
Neither FASTA nor FASTQ stores genomic coordinates. A FASTA file holds named sequences with no quality information. A FASTQ file holds the same sequences plus a per-base quality string encoded as ASCII characters offset by 33, which is the Phred+33 convention used by Illumina and most modern platforms.
Coordinates enter the picture only when reads are aligned. FASTQ reads are mapped to a FASTA reference, and the aligner writes SAM or BAM records with 1-based positions against that specific FASTA file. Annotations in GFF, GTF, or BED are likewise anchored to a specific assembly version. This is why the reference file is not interchangeable. A BED file built against GRCh38 patch 12 and a FASTA from patch 14 are not the same coordinate system in the places where they differ, and a BED file built against hg19 is a different universe from one built against hg38.
The practical rule: a BED file has no meaning without the assembly and the exact FASTA it was built against. Record both, or the file will eventually produce a coordinate error that no amount of debugging can resolve because the missing information was never written down.
Coordinate Error Triage Table
Work down this table in order. The upper rows account for most real-world failures.
| Symptom | Likely cause | How to confirm | Fix |
|---|---|---|---|
| Every feature shifted one base right | 1-based start not decremented | Compare one feature against its GFF or GTF source | Subtract 1 from column 2 only |
| Feature lengths all one base short | End decremented along with start | Recompute end - start for a known exon | Leave the end column unchanged during conversion |
| Feature lengths all one base long | Inclusive end converted by adding 1 | Compare to source annotation length | Convert with start - 1 and end |
bedtools intersect returns nothing, no error | Chromosome naming mismatch | Compare cut -f1 of both files | Harmonize chr prefixes and MT versus chrM |
| Error naming an out-of-order record | Unsorted input to a sorted-mode tool | Run sort -k1,1 -k2,2n and compare with cmp | Sort with the same key and locale |
| Malformed BED entry, start greater than end | Swapped columns or double subtraction | Check $2 >= $3 with awk | Swap back, or clip negatives to zero |
| Warning that a chromosome is not in the FASTA | BED names do not match the FASTA index | Compare against ref.fa.fai | Rename chromosomes or rebuild the BED |
| Web browser shows features one base wide | Zero-length interval written for an insertion | Check $2 == $3 | Widen to 1 bp for interval operations |
| All intervals map to the wrong region after liftover | Reversed chain file or wrong assembly | Check the unmapped output fraction | Use the correctly directed chain |
| Score column errors or odd colors | Values outside 0 to 1000 | Print min and max of column 5 | Rescale or move the value to the name field |
| Tool reads one giant column | Spaces instead of tabs, or CRLF line endings | Run file and check field counts | Convert delimiters and strip carriage returns |
| Exon counts wrong for a BED12 file | blockCount does not match block arrays | Count comma-separated entries per row | Rebuild the BED12 from a gene model |
Causes, Mechanisms, and Fixes
1. Off-by-one from a 1-based source
This is the dominant cause. A GFF, GTF, VCF, SAM, or BAM file was converted to BED, and the start coordinate was written without subtracting 1. Every feature in the output is shifted one base to the right.
The mechanism is simple. The start value in the source names the first base of the feature, counting the first base of the chromosome as 1. BED names the position before the first base of the feature, counting the first base of the chromosome as 0. Those two numbers differ by exactly one for every feature.
The consequences are subtle enough to survive casual inspection. Overlap counts drop slightly because features that should abut now leave a one-base gap. Variant annotation misses any variant that sits on the first base of an exon, a codon, or a regulatory element. Primer design extends one base into the flanking sequence. Motif scanning shifts every hit.
Take a GFF3 exon at bases 101 to 200. The correct BED record is chr1 100 200 exon1 . +. The buggy record is chr1 101 200 exon1 . +, which describes 99 bases instead of 100. The file validates. The length is wrong. The biology downstream is wrong.
Confirm the error by extracting sequence both ways. Build a one-line BED from a feature whose sequence you know, then run:
samtools faidx genome.fa chr1:101-200
bedtools getfasta -fi genome.fa -bed exon.bed -fo stdout
The two sequences must be identical. If the BED output begins one base later, the start was not decremented. If it begins one base earlier, it was decremented twice. Note that samtools faidx takes 1-based inclusive regions from the command line, so chr1:101-200 is the correct query for a feature spanning bases 101 through 200.
2. The end coordinate treated as inclusive
The mirror-image mistake is subtracting 1 from the end column during the same conversion. Because GFF's end is inclusive and BED's end is exclusive, the correct transformation is start - 1 and end with the end unchanged. Decrementing both drops the last base of every feature.
The arithmetic is unforgiving. A 100-base exon at 101 to 200 becomes 100 199, which is 99 bases. A gene model with 20 exons loses 20 bases. A coding sequence loses one base per exon, and unless the loss happens to preserve the reading frame, the predicted protein changes.
The reverse error appears when exporting BED back to GFF. Adding 1 to the end produces features one base too long. Two round trips of a badly written converter can turn a 250-base exon into 252 bases.
Check the invariant: chromEnd - chromStart must equal the feature length you expect from the source annotation. Run this over a few known features and the error will be obvious.
3. Chromosome naming mismatches
Two files can use perfectly correct BED coordinates and still produce zero overlaps because their chromosome names come from different naming authorities.
UCSC style uses chr1, chr2, and chrM, plus names for alternate and random contigs such as chr1_KI270706v1_random. Ensembl style uses 1, 2, and MT, and names scaffolds without the chr prefix. NCBI RefSeq style uses accessions such as NC_000001.11, with patch contigs named NZ_.... GENCODE ships with the chr prefix. Ensembl GTF ships without it.
The failure mode is silent. bedtools intersect reports zero intervals and exits cleanly. bedtools getfasta prints a warning of the form WARNING. chromosome (chr1) was not found in the FASTA file. Skipping. and produces an empty or truncated output. A plotting script renders an empty chromosome ideogram. Nothing crashes, which is why this error survives for so long.
Confirm it in three commands:
cut -f1 sample.bed | sort -u > bed_chroms.txt
cut -f1 reference.fa.fai | sort -u > ref_chroms.txt
comm -23 bed_chroms.txt ref_chroms.txt
Lines printed by comm exist in the BED file but not in the reference index. Those are your orphans.
Fix by harmonizing to the reference. To strip a prefix:
awk 'BEGIN{OFS="\t"} {sub(/^chr/, "", $1)
print}' input.bed > stripped.bed
To add one, with a guard against double prefixing:
awk 'BEGIN{OFS="\t"} $1 !~ /^chr/ {$1 = "chr" $1}
1' input.bed > prefixed.bed
Handle the mitochondrial name explicitly, because chrM in UCSC corresponds to MT in Ensembl and to chrM in many RefSeq-derived files. Rather than chaining sed commands that will eventually break, build a two-column mapping table from your reference index and join it onto the BED file. That table becomes a permanent, reviewable artifact.
4. Unsorted records where sorted input is required
Several operations in bedtools, including intersect with the sorted mode, merge, closest, subtract, and map, require both inputs to be sorted in a consistent way. When they are not, bedtools emits an error naming the file and the out-of-order record.
Sorting a BED file is not the same as sorting a list of words. The correct key sorts chromosome names lexicographically and then start positions numerically:
sort -k1,1 -k2,2n input.bed > sorted.bed
Two subtleties cause most remaining failures. First, locale settings can change the order of punctuation and mixed-case names, so pin the locale with LC_ALL=C. Second, when a genome file is supplied through the -g option, the chromosome order must follow the genome file rather than the alphabet, because bedtools compares chromosome order between files positionally. Mixing an alphabetic sort in one file with a genome-file sort in another produces an out-of-order error even though both files are internally sorted.
The simplest defense is to sort every BED with the same command every time, and to prefer bedtools sort -faidx reference.fa.fai -i input.bed when a reference index is available, because that produces an order consistent with the FASTA.
5. Start greater than end, or a negative start
Swapped columns, double subtraction, and manual edits all produce intervals where the start exceeds the end. Bedtools rejects these with a message identifying the file and line as a malformed BED entry, which is one of the more helpful errors in the ecosystem.
Two commands isolate the problem:
awk -F'\t' '$2 >= $3 {print FNR": "$0}' input.bed
awk -F'\t' '$2 < 0 || $3 < 0 {print FNR": "$0}' input.bed
Negative starts appear when a converter subtracts 1 from a start that was already 0, which can happen after a partial conversion or in a liftover step. UCSC liftOver can also emit intervals that extend past the beginning of a contig when a feature near the start of the source assembly maps across an alignment gap.
Repair with an awk pass that clamps and reorders:
awk -F'\t' 'BEGIN{OFS="\t"}
$2 < 0 { $2 = 0 }
$2 > $3 { temp = $2
$2 = $3
$3 = temp }
1' input.bed > repaired.bed
Log how many rows were changed. Silent repair hides upstream bugs that will return.
6. Intervals beyond the chromosome ends
A BED interval that claims to end past the last base of its chromosome usually means the file was built against a different assembly or a different contig set. The most common scenario is a BED file built from an annotation that includes decoy or alternate contigs used against a FASTA that omits them, or the reverse.
Some tools clip such intervals without complaint. Others produce empty sequences while still emitting records. The variation is worse than an error, because it makes the problem invisible.
Join the BED against a chromosome sizes file derived from the reference index:
cut -f1,2 reference.fa.fai > chrom.sizes
awk 'BEGIN{OFS="\t"}
NR == FNR { size[$1] = $2
next }
!($1 in size) || $3 > size[$1] || $2 < 0 { print FNR": "$0 }
' chrom.sizes input.bed
If the report is empty, your intervals fit. If it is not, decide deliberately whether to drop or clip. Dropping preserves honesty. Clipping preserves record count. Either way, write the count to a log.
7. Assembly mismatch and reversed liftOver chains
Coordinate liftover converts a feature from one assembly to another through a chain file that records aligned blocks. The direction of the chain file is easy to get wrong. A file named hg38ToHg19.over.chain.gz converts hg38 coordinates into hg19 coordinates. Applying it to an hg19 BED file produces output that looks structurally valid and is biologically meaningless.
Liftover also does not preserve length. When a feature spans an alignment gap between the two assemblies, the mapping splits or truncates it. Insertions and deletions in the chain can change the length of a mapped interval by several bases. This is not a bug, and it is one of the reasons lifted coordinates should be treated as approximate near gaps.
Detect the problem by checking a landmark. Pick a well-characterized feature with a published coordinate in the target assembly and confirm that the lifted interval lands within a few kilobases. If nearly everything falls in the unmapped output file instead, the chain direction is probably reversed.
CrossMap provides a maintained route for BED, GFF, GTF, VCF, and bigWig conversion between assemblies, and it writes unmapped records to a separate file so failures are visible rather than lost. UCSC liftOver remains the reference implementation for BED and is available as a web tool and a command-line binary.
Safety note: never write the liftover output over the input file. A reversed or truncated chain applied in place destroys the only copy of coordinates that cannot be reconstructed. Keep the unmapped file alongside the mapped output and record the chain filename and checksum in the analysis log.
8. Parsing failures: delimiters, headers, and mixed BED flavors
BED requires tab delimiters. Files exported through spreadsheet software frequently contain spaces, and files transferred through Windows systems frequently contain carriage returns at the end of every line. Both produce parsers that see a single column or a truncated field.
Diagnose the shape of the file first:
awk -F'\t' '{print NF}' input.bed | sort -n | uniq -c
A healthy BED3 or BED6 file reports a single field count. Mixed counts mean mixed flavors within one file, which is legal in a loose sense and dangerous in practice.
Check line endings and encoding:
file input.bed
head -1 input.bed | od -c | head
If file reports CRLF, strip the carriage returns with sed 's/\r$//' or dos2unix before anything else touches the file.
Header lines are the other persistent offender. BED permits track and browser lines for the UCSC browser, and comment lines beginning with # are tolerated by some parsers. Strict parsers reject all of them. Strip them at the start of the pipeline, not in the middle.
Finally, check for a GFF file that was renamed to .bed. The third column test settles it instantly. If column three contains a word such as exon, gene, or mRNA, the file is GFF and needs a real conversion.
9. BED12 block and thick-field inconsistencies
BED12 adds exon structure. The rules from the UCSC specification are strict. blockCount must equal the number of entries in blockSizes and the number of entries in blockStarts. Both arrays are terminated by a trailing comma. The sizes are lengths, the starts are offsets measured from chromStart, and the blocks must fall inside chromStart to chromEnd without overlapping. thickStart and thickEnd define the coding region and should coincide with block boundaries for a coherent gene model.
Hand-editing BED12 records almost always breaks one of these rules. The visible symptom is a browser that renders exons in the wrong places, or a downstream tool that counts the wrong number of exons. Some tools silently ignore blockCount and use whichever array is shorter.
Check the arrays with awk by counting comma-separated tokens:
awk -F'\t' 'NF == 12 {
n = split($11, a, ",")
m = split($12, b, ",")
if (n - 1 != $10 || m - 1 != $10) print FNR": "$0
}' input.bed
The minus one accounts for the trailing comma, which produces an empty final token.
Rebuild rather than repair. Converting a GFF3 or GTF file with a maintained converter produces BED12 records that satisfy the block rules, and regenerating is faster than chasing individual broken records.
10. Zero-length intervals and insertion points
BED permits chromStart to equal chromEnd to represent an insertion point, which has zero width on the reference. Some tools honor this convention, some treat it as a malformed record, and some draw a one-pixel feature that looks like a coordinate error.
Zero-length intervals appear most often when a VCF file is converted to BED. An insertion has a REF allele of length 1 and an inserted sequence in ALT, so a naive conversion using REF length produces a one-base interval, while a conversion that uses POS twice produces a zero-length point.
For interval operations such as overlap counting or feature merging, widen zero-length features by one base on each side and record that decision. For visualization, leave them as points. Do not mix the two conventions within one analysis.
11. Misused optional fields
The BED score column is defined as an integer from 0 to 1000. It is not a Phred quality, not a p-value, and not a read count. Files that carry raw counts or negative log p-values in column five produce sorting errors in tools that parse it as a number, and rendering artifacts in browsers that map the score to a color ramp.
Fix by rescaling into range, or by moving the value into the name field where it is free text. For negative log p-values, an offset transform into the 0 to 1000 range preserves ordering and keeps the file valid:
awk 'BEGIN{OFS="\t", max=0}
NR > 1 && $5 > max { max = $5 }
{ line[NR] = $0
score[NR] = $5
chrom[NR] = $1 }
END { for (i = 1
i <= NR
i++) { print line[i] } }
' input.bed
In practice, the simpler route is to divide by the maximum and multiply by 1000, or to keep scores out of column five entirely.
The itemRgb field must be three integers from 0 to 255 separated by commas. This field is one of the most common sources of browser rendering complaints.
12. Silent clipping and rounding downstream
Some tools accept out-of-range coordinates and clip them without a message. Others convert BED to an internal 1-based representation, perform an operation, and convert back, losing a base at one end if the conversion is asymmetric. BED-to-BAM conversion tools must round zero-length features to at least one base, because BAM cannot represent a zero-length alignment.
The general defense is to verify the round trip. Take a BED file, run it through the tool in question and back to BED, and compare:
bedtools intersect -a input.bed -b input.bed -wa > roundtrip.bed
cmp input.bed roundtrip.bed
A self-intersection with the -wa flag returns the original intervals unchanged when nothing is clipped. Any difference points at the tool.
A Ten-Step Diagnostic Sequence
Run these in order and stop at the first failure.
- Confirm the field count is uniform.
awk -F'\t' '{print NF}' input.bed | sort -n | uniq -cshould show one line. - Confirm the file uses tabs and Unix line endings.
file input.bedshould not report CRLF. - Confirm there are no
track,browser,#, or blank lines in the middle of the file. - Confirm the third column is numeric, which rules out a mislabeled GFF file.
- Confirm no row has
start >= end, and no row has a negative coordinate. - Compare chromosome names against
cut -f1 reference.fa.faiand resolve every orphan. - Compare the maximum end coordinate per chromosome against the chromosome sizes.
- Confirm the file is sorted in the order the downstream tool expects, using the same locale and the same genome file.
- Extract sequence for one known feature with both
samtools faidxandbedtools getfastaand compare the outputs base for base. - Confirm the assembly and annotation version recorded for the BED matches the FASTA and the chain file in use.
That sequence resolves most coordinate errors in under five minutes. It also produces an audit trail that is worth keeping.
Repair Recipes
Convert GFF3 to BED3 or BED6. The start is decremented, the end is untouched, and the score field is set to 0 because GFF scores are frequently a dot:
awk -F'\t' 'BEGIN{OFS="\t"} !/^#/ && NF >= 9 {print $1, $4 - 1, $5, $3, 0, $7}' genes.gff3 > genes.bed
Convert GTF to BED6. GTF has the same nine-column layout as GFF2, with attributes in column nine:
awk -F'\t' 'BEGIN{OFS="\t"} !/^#/ && NF >= 9 {print $1, $4 - 1, $5, $3, 0, $7}' genes.gtf > genes.bed
Convert VCF to BED for variants. The end is computed from the REF allele length so deletions and insertions span correctly:
bcftools query -f '%CHROM\t%POS\t%REF\n' variants.vcf \
| awk 'BEGIN{OFS="\t"} {print $1, $2 - 1, $2 - 1 + length($3)}' > variants.bed
Rebuild a chromosome sizes file from the FASTA index:
samtools faidx reference.fa
cut -f1,2 reference.fa.fai > chrom.sizes
Clip intervals to chromosome bounds while logging how many rows changed:
awk 'BEGIN{OFS="\t"}
NR == FNR { size[$1] = $2
next }
{
changed = 0
if (!($1 in size)) { next }
if ($2 < 0) { $2 = 0
changed = 1 }
if ($3 > size[$1]) { $3 = size[$1]
changed = 1 }
if (changed) { print > "clipped.log" }
print
}' chrom.sizes input.bed > clipped.bed
Sort consistently before any sorted-mode operation:
LC_ALL=C sort -k1,1 -k2,2n input.bed > sorted.bed
bedtools intersect -sorted -a sorted.bed -b regions.bed -wa -wb
Prevention Practices
Coordinate errors are cheap to prevent and expensive to diagnose. The practices below remove most of the opportunity for them.
Keep the conversion in exactly one place. Write one script that converts GFF, GTF, or VCF into BED, commit it, and use it for every project. Ad hoc one-liners typed at a prompt are the main source of inconsistent conversions across a lab.
Record the assembly and annotation version in a companion file next to every BED. A short text file naming the FASTA, its checksum, the annotation release, and the conversion script version is enough. Six months later, that file will be the difference between a reproducible result and an unreproducible one.
Validate on ingest. Run the field-count check, the bounds check, and the chromosome-name comparison as part of the pipeline that creates the BED file, not as a manual step. A validation step that fails the pipeline is worth more than a validation step that prints a warning.
Test with a one-base feature. A BED record for a single base at one-based position 100 is chr1 99 100. If a pipeline handles that correctly through every stage, most off-by-one problems are already excluded.
Prefer BED12 for gene models and BED6 for intervals. Do not mix them in one file, and do not add optional columns that downstream tools will misinterpret as score or strand.
Use the reference index as the authority for chromosome names and lengths. The .fai file created by samtools faidx is the ground truth for what your FASTA actually contains, and every naming decision should be reconciled against it.
Common Mistakes and Limitations
Assuming all annotation files share a coordinate system. They do not. GFF, GTF, VCF, and SAM are 1-based. BED and BAM are 0-based. Mixing them without conversion is the root cause behind most of this article.
Subtracting 1 from both start and end. This is the single most common repair attempt that makes things worse. Only the start changes.
Sorting with a plain sort and no key. Default sorting compares the whole line as a string, which puts chr10 before chr2 in some contexts and produces a file that fails the sorted-input check even though it looks ordered to a human.
Assuming a chr prefix exists everywhere. Ensembl and NCBI do not use it. Hardcoding a sed 's/^/chr/' across a mixed set of files will double-prefix some of them.
Reusing a BED file across assemblies. Coordinates from hg19 applied to hg38 produce plausible numbers and wrong biology. There is no validation step that catches this reliably, because the file is syntactically valid.
Trusting liftover to preserve feature length. Chain files contain gaps, and features that span gaps change length or split. Any analysis sensitive to exact exon length needs re-derivation from the target assembly annotation rather than liftover.
Assuming a zero-length interval is portable. Some tools accept insertion points, some reject them, and some silently convert them to one base.
Assuming all BED parsers agree on optional columns. The core three columns are universal. Columns four through twelve are interpreted differently by different tools, and a file that satisfies one parser may be rejected by another.
Treating a clean tool exit as proof of correct coordinates. Several of the errors described here produce no error message at all. The absence of a crash is not evidence of correctness.
Limitations: individual datasets vary. A pipeline that is correct for one annotation release may need a naming update for the next one. Validate against your own reference rather than trusting a previous project's conventions, and treat any coordinate discrepancy that affects a reported result as something to resolve at the source rather than patch downstream.
Frequently Asked Questions
Why is my BED file off by one?
Your start coordinate almost certainly came from a 1-based file without subtracting 1. Compare one BED record against the GFF, GTF, or VCF line it was built from. If the start value is identical rather than one less, that is the error.
Is BED 0-based or 1-based?
BED is 0-based for the start and exclusive for the end. The first base of a chromosome is numbered 0, and the end coordinate names the first base that is not part of the feature. Nearly every other genomics format counts from 1 and includes the end base.
How do I convert a GTF file to BED without shifting coordinates?
Subtract 1 from column four only, and copy column five unchanged. Column four becomes chromStart, column five becomes chromEnd, and the resulting feature length equals end - start with no plus-one term.
Why does bedtools intersect return zero overlaps when both files look correct?
The chromosome names in the two files probably disagree. Compare the unique values of column one in each file with comm. Names like chr1 and 1 describe the same chromosome but never match as strings.
What does a malformed BED entry error mean?
It means a line could not be parsed as a valid interval, most often because the start exceeds the end, a coordinate is negative, a field is missing, or the delimiter is a space rather than a tab. The error usually names the file and line number, so inspect that record directly.
Do I need to sort my BED file?
Only for operations that require sorted input, which include merge, closest, subtract, map, and intersect in sorted mode. Use the same sort key and locale for every file in the comparison, and follow the genome file order when one is supplied.
How do I check whether my BED coordinates match my FASTA reference?
Extract sequence for one feature with both samtools faidx and bedtools getfasta and compare the outputs. Identical sequences confirm that the coordinates, the naming, and the assembly all agree. A one-base difference points to a conversion error.
Can I use hg19 BED coordinates with an hg38 genome?
No. The coordinates refer to different assemblies and will map to the wrong genomic positions. Convert with a properly directed chain file, or rebuild the BED from an hg38 annotation, and treat lifted coordinates near alignment gaps as approximate.