Getting Cell Ranger to Accept Your FASTQ Files
By the end of this you will have a directory of FASTQ files that cellranger count recognizes without argument, a set of pre-flight checks that catch the three or four things that go wrong, and a finished run with a feature-barcode matrix and a position-sorted BAM. You need: Cell Ranger 8.0 or 9.0 (a single tarball, no dependencies beyond a 64-bit Linux host), a 10x reference or the files to build one, roughly 8 cores and 64 GB of RAM for a standard 3’ gene expression sample, and 1–2 TB of scratch. If you are starting from BCLs you also need either cellranger mkfastq (which wraps Illumina’s converter) or BCL Convert installed separately. If you are starting from a public BAM, you need bamtofastq from the 10x binaries.
1. Understand what Cell Ranger is looking for
Cell Ranger does not scan a directory for anything that ends in .fastq.gz. It globs for a specific pattern:
[Sample]_S[Number]_L00[Lane]_[Read]_001.fastq.gz
For example:
PBMC_healthy_S1_L001_R1_001.fastq.gz
PBMC_healthy_S1_L001_R2_001.fastq.gz
PBMC_healthy_S1_L001_I1_001.fastq.gz
PBMC_healthy_S1_L001_I2_001.fastq.gz
Every field matters. S1 is the sample index within the flowcell demultiplex, not a sample identifier you choose. The lane must be three digits. The trailing _001 is a fixed chunk number from Illumina’s converter and must be present. The read token is one of R1, R2, I1, I2. Uncompressed .fastq works too, but compress them; the pipeline reads gzip natively and you will not be I/O bound.
Two flags control selection. --fastqs is a directory (or comma-separated directories, one per flowcell). --sample is the prefix before _S[Number], and it is matched exactly. If your file is PBMC_healthy_S1_L001_R1_001.fastq.gz, then --sample=PBMC_healthy. Not PBMC, not PBMC_healthy_S1. Underscores inside the sample name are fine, which is why the parser anchors on _S<digits>_L<digits>_.
You can pass --sample=A,B,C to merge several demultiplexed samples into one run. Do that only when they are the same GEM well sequenced under different index names. Merging distinct GEM wells produces barcode collisions and a meaningless matrix.
Also know the read structure, because Cell Ranger will check it:
| Chemistry | R1 | Content | R2 |
|---|---|---|---|
| 3’ v2 | 26 bp | 16 bp barcode + 10 bp UMI | ≥ 25 bp cDNA |
| 3’ v3 / v3.1 | 28 bp | 16 bp barcode + 12 bp UMI | ≥ 25 bp cDNA |
| 5’ v2 | 26 bp | 16 bp barcode + 10 bp UMI | ≥ 25 bp cDNA |
R2 is the biological read. R2 longer than 90 bp buys you very little for 3’ counting because alignment is to a transcriptome and reads are already unambiguous; 90 bp is the standard and fine.
2. Produce FASTQs from BCLs (if you have them)
If your core handed you FASTQs, skip to step 3. If you have a run directory, you have two paths.
cellranger mkfastq is the path of least resistance because it knows the 10x index sets. Write a simple CSV:
Lane,Sample,Index
*,PBMC_healthy,SI-TT-A1
Then:
cellranger mkfastq \
--id=mkfastq_run1 \
--run=/data/runs/250901_A00123_0456_AHXXXXDRXX \
--csv=simple.csv \
--localcores=16 \
--localmem=64
SI-TT-A1 expands to a dual-index pair internally. For older single-index kits (SI-GA-*), it expands to four distinct i7 sequences, which is why single-index 10x samples occupy four index slots on a flowcell.
If your site standardized on BCL Convert, use it directly and control cycles explicitly. This is the version we use, because OverrideCycles makes the read structure legible in the sample sheet instead of implied:
[Settings]
OverrideCycles,Y28;I10;I10;Y90
CreateFastqForIndexReads,1
[BCLConvert_Data]
Lane,Sample_ID,index,index2
1,PBMC_healthy,AGCGGATCAT,TCTGCTAATC
Two notes. Set CreateFastqForIndexReads,1 whenever you might later run Feature Barcoding or need to audit index hopping; the I1/I2 files cost little and Cell Ranger ignores them if unused. Do not let the converter adapter-trim to zero length: with bcl2fastq you want --minimum-trimmed-read-length 8 --mask-short-adapter-reads 8, otherwise short reads get emitted with length zero and Cell Ranger’s R1/R2 length check will reject the chunk.
If your input is a public 10x BAM (GEO submissions often post these), reconstruct the original reads rather than trying to re-derive them:
bamtofastq --nthreads=8 possorted_genome_bam.bam ./fastq_out/
It writes a directory tree already in the [Sample]_S1_L00X_R1_001.fastq.gz form, with the original barcode and UMI reads reconstituted from BAM tags.
3. Verify the FASTQs before you spend eight hours of compute
Four checks. They take two minutes and catch most of what goes wrong.
Integrity first. Truncated transfers are the single most common cause of a run dying at 90%:
for f in *.fastq.gz; do gzip -t "$f" || echo "CORRUPT: $f"; done
md5sum -c checksums.md5
Read lengths second. Cell Ranger aborts on mixed R1 lengths within a sample, so look before you run:
zcat PBMC_healthy_S1_L001_R1_001.fastq.gz | head -400000 \
| awk 'NR%4==2 {print length($0)}' | sort -n | uniq -c
You want a single value: 28 for 3’ v3, 26 for v2 or 5’. A spread of lengths means the converter trimmed adapters out of R1.
Read counts third. R1 and R2 must have the same number of records, in the same order:
for r in R1 R2; do
echo -n "$r: "
zcat PBMC_healthy_S1_L001_${r}_001.fastq.gz | wc -l | awk '{print $1/4}'
done
Barcode plausibility fourth. This is the check nobody runs and it will save you a whole run. Pull the first 16 bases of R1 and compare against the whitelist that ships with Cell Ranger (737K-august-2016.txt for v2, 3M-february-2018.txt.gz for v3):
WL=$(dirname $(readlink -f $(which cellranger)))/lib/python/cellranger/barcodes/3M-february-2018.txt.gz
zcat PBMC_healthy_S1_L001_R1_001.fastq.gz | head -400000 \
| awk 'NR%4==2 {print substr($0,1,16)}' | sort -u > obs_bc.txt
zcat "$WL" | cut -f1 | sort -u > wl.txt
comm -12 obs_bc.txt wl.txt | wc -l
wc -l < obs_bc.txt
If the overlap fraction is under about 50%, you have the wrong chemistry, R1 and R2 swapped, or reverse-complemented barcodes from a converter misconfiguration. Stop and fix it.
A note on sequencers: 10x libraries run on non-Illumina platforms are viable but not identical. A direct comparison of NovaSeq 6000 and MGISEQ 2000 on matched 10x libraries found broadly concordant cell calls and expression, with platform-specific differences in error profile and duplication that matter most if you are merging data across instruments 1. If your longitudinal samples straddle platforms, treat instrument as a batch covariate rather than assuming it away.
4. Get a reference
Use the prebuilt human reference unless you need something it lacks:
curl -O https://cf.10xgenomics.com/supp/cell-exp/refdata-gex-GRCh38-2024-A.tar.gz
tar -xzf refdata-gex-GRCh38-2024-A.tar.gz
Build your own only for a real reason: a transgene, a viral genome, a custom annotation. The recipe is cellranger mkgtf to filter biotypes, then cellranger mkref:
cellranger mkgtf genes.gtf genes.filtered.gtf \
--attribute=gene_biotype:protein_coding \
--attribute=gene_biotype:lncRNA \
--attribute=gene_biotype:IG_C_gene \
--attribute=gene_biotype:TR_C_gene
cellranger mkref \
--genome=GRCh38_custom \
--fasta=genome.fa \
--genes=genes.filtered.gtf \
--nthreads=16
mkref on a human genome needs about 32 GB of RAM and an hour. Filtering biotypes matters more than people expect: leaving in all the pseudogene and retained-intron entries inflates multimapping and drags down the confidently-mapped rate.
5. Run cellranger count
cellranger count \
--id=pbmc_healthy_run1 \
--transcriptome=/refs/refdata-gex-GRCh38-2024-A \
--fastqs=/data/fastq/HXXXXDRXX,/data/fastq/HYYYYDRXX \
--sample=PBMC_healthy \
--create-bam=true \
--localcores=16 \
--localmem=128
Flag by flag, with opinions:
--create-bam is required in Cell Ranger 8.0+ and has no default. Set it to true. The BAM costs disk but it is what you need for velocity-style spliced/unspliced quantification, for allele-specific work, and for any later question about where a read landed. Once you throw it away you cannot get it back without re-running.
--chemistry defaults to auto and auto-detection is reliable when barcodes match the whitelist. Pin it (--chemistry=SC3Pv3) only when detection fails, which usually means something else is wrong.
--include-introns defaults to true from version 7.0 onward. Leave it on for nuclei and for tissue with high nuclear RNA content. Turn it off only when comparing against an older dataset processed without it, because the count distributions differ enough to confound.
Skip --expect-cells unless you have a reason. The cell-calling algorithm handles a wide range. --force-cells is a blunt instrument for rescuing a failed call and should be a last resort, chosen from the barcode-rank plot, not from a guess.
Wall clock on 16 cores for 300M read pairs is roughly 3–6 hours, dominated by alignment.
6. Read the metrics before you read the biology
Open outs/web_summary.html and outs/metrics_summary.csv. The numbers that tell you whether the FASTQs were right:
- Valid barcodes. Should be above roughly 75%. Below that points at a chemistry mismatch or a demultiplexing error, not at your sample.
- Q30 bases in barcode and in UMI. Above roughly 90% and 75% respectively. Low barcode Q30 with normal R2 quality often means a cycle problem in the first 16 cycles of R1.
- Reads mapped confidently to transcriptome. For a good human 3’ library this sits in the 60–80% range. A collapse here with normal barcode metrics means a reference problem: wrong species, wrong build, over-inclusive GTF.
- Fraction reads in cells. Below about 50% indicates substantial ambient RNA from lysed cells, which is a wet-lab signal, not a pipeline bug.
- Sequencing saturation. If it is under 40%, more sequencing on the same library will still return new UMIs.
Keep metrics_summary.csv from every run in one table. Across a longitudinal profile, drift in these metrics is usually the first sign that a batch differed.
7. Take the outputs further
outs/ gives you filtered_feature_bc_matrix/ (cell-called barcodes), raw_feature_bc_matrix/ (all barcodes, including empty droplets), molecule_info.h5, and possorted_genome_bam.bam.
Do not discard the raw matrix. Ambient RNA correction methods estimate the soup from the empty droplets, and you need both matrices. FastCAR uses the barcode-rank profile to determine an ambient RNA expression profile from empty droplets and subtracts a per-gene contamination estimate, which materially changes downstream differential expression calls 2. Run it, or an equivalent, before you interpret any low-expression gene.
For spliced and unspliced counts, the classic route is velocyto run10x against the BAM, which is slow and memory-hungry on large samples. tidesurf reads the same Cell Ranger BAM and produces spliced and unspliced count matrices with markedly better runtime and memory behavior while remaining accurate against established quantification, and it handles multi-sample input directly 3. That is what we use now.
tidesurf --orientation sense -o tidesurf_out ./pbmc_healthy_run1 genes.gtf
Everything downstream (normalization, clustering, integration) is your choice of Scanpy or Seurat and outside this guide.
Common problems
“No input FASTQs were found for the requested parameters.” In order of likelihood: the --sample prefix does not exactly match the text before _S<digits>; the files lack the _001 suffix; the lane is L1 instead of L001; you pointed --fastqs at the parent directory instead of the one holding the files. Cell Ranger does not recurse. Run ls in the exact path you passed and check the pattern character by character. If the core delivered Sample1_R1.fastq.gz, rename with a loop rather than symlinking selectively, and keep an original_names.tsv mapping so the rename is reversible.
Mixed R1 lengths. Caused by adapter trimming during conversion. Re-convert with --minimum-trimmed-read-length 8 --mask-short-adapter-reads 8 under bcl2fastq, or fix OverrideCycles under BCL Convert. Truncating R1 to a uniform length yourself works mechanically but throws away UMI bases and inflates the apparent duplicate rate, so re-convert if you can.
Chemistry auto-detection failure. The message names the ambiguity. Check the barcode overlap from step 3 before pinning --chemistry. If the overlap is high but detection still fails, it is usually a low-complexity or very small FASTQ; pinning is then safe.
R1 and R2 swapped. Barcode overlap near zero, valid barcodes near zero, mapping rate near zero. Some cores emit reads as R1/R3 with the index as R2. Rename so the 28 bp read is R1 and the cDNA read is R2.
Multiple flowcells, duplicate sample indices. If the same sample was sequenced on two flowcells, pass both directories to --fastqs separated by a comma. Do not copy both sets of files into one directory: both will be S1_L001 and one silently overwrites the other. If you must consolidate, renumber the S field.
Sample sheet index mismatch on a NovaSeq with i5 reverse complement. Dual-index workstations differ in i5 orientation between instrument generations. Symptom: near-zero reads assigned, everything in Undetermined. Use the 10x index set names with mkfastq, which handles orientation, or reverse-complement index2 in your BCL Convert sheet and re-run conversion on a single tile to test quickly.
Running out of memory at the STAR step. A human reference needs about 32 GB resident. --localmem is a ceiling you declare, not an allocation. If the host has less than you claimed, the job is killed by the OOM reaper with a message that looks unrelated. Check dmesg.
Nothing here is a clinical result. Cell counts, expression matrices, and ambient-corrected differential expression are measurements. Any interpretation bearing on your health belongs with a clinician who can see the rest of your record.
Oak builds longitudinal molecular profiles of individuals: whole-genome sequencing, RNA sequencing, proteomics, blood biomarkers, and continuous glucose data, integrated into one model of you. Build your profile.
Footnotes
-
Weiran Chen, Md Wahiduzzaman, Quan Li, et al. Comparative analysis of NovaSeq 6000 and MGISEQ 2000 single‐cell RNA sequencing data. Quantitative Biology, 2022. https://doi.org/10.15302/j-qb-022-0295 ↩
-
Marijn Berg, Ilya Petoukhov, Inge van den Ende, et al. FastCAR: fast correction for ambient RNA to facilitate differential gene expression analysis in single-cell RNA-sequencing datasets. BMC Genomics, 2023. https://doi.org/10.1186/s12864-023-09822-3 ↩
-
Jan T. Schleicher, Doreen Klingler, Manfred Claassen. Accurate quantification of spliced and unspliced transcripts for single-cell RNA sequencing with tidesurf. PLOS One, 2026. https://doi.org/10.1371/journal.pone.0355867 ↩