Cutadapt trim-paired with separate 5'/3' adapters retaining primers — is switching to linked adapters the correct fix?

Hi all,

I'm processing paired-end NovaSeq metabarcoding data (marine vertebrate 16S marker, MarVer3 primers; ~245 bp amplicon, ~209 bp insert, sequenced 2×250) and discovered that my cutadapt trim-paired step was leaving the 5' primer attached on a large fraction of surviving reads. I'd like to confirm my understanding of the cause and validate my proposed fix before I re-run the whole downstream pipeline.

Original command (QIIME2 2026.1):

qiime cutadapt trim-paired \
  --i-demultiplexed-sequences paired-end-demux.qza \
  --p-front-f AGACGAGAAGACCCTRTG \
  --p-adapter-f GGGATAACAGCGCAATCC \
  --p-front-r GGATTGCGCTGTTATCCC \
  --p-adapter-r CAYAGGGTCTTCTCGTCT \
  --p-error-rate 0.1 \
  --p-overlap 3 \
  --p-discard-untrimmed \
  --p-cores 4 \
  --o-trimmed-sequences trimmed-seqs-default.qza \
  --verbose

Here --p-front-f/--p-front-r are the forward/reverse primers (5') and --p-adapter-f/--p-adapter-r are the reverse-complements of the opposite primers (the 3' read-through, since reads are longer than the insert).

The problem. I exported the trimmed reads and re-scanned them for the 5' primer using cutadapt with --action=none (detect-only, no trimming), applying the same error rate and overlap:

cutadapt -g AGACGAGAAGACCCTRTG -e 0.1 -O 3 --action=none -o /dev/null allR1.fastq.gz
cutadapt -g GGATTGCGCTGTTATCCC -e 0.1 -O 3 --action=none -o /dev/null allR2.fastq.gz

Result: 42.5% of R1 reads and 43.4% of R2 reads still had the 5' primer present after trimming.

My understanding of the cause: Passing --p-front-f and --p-adapter-f as separate adapters makes cutadapt treat them as alternatives: with --p-times at its default of 1, it removes only the single best-scoring match per read. Since most reads contain both the 5' primer and the 3' read-through, on ~43% of reads the 3' read-through scored best and was removed, leaving the 5' primer in place. Because some adapter was removed, the read was marked "trimmed," so --p-discard-untrimmed kept it. In other words, --p-discard-untrimmed here enforces "some adapter was removed," not "the 5' primer was removed."

Proposed fix — linked adapters:

qiime cutadapt trim-paired \
  --i-demultiplexed-sequences paired-end-demux.qza \
  --p-front-f "AGACGAGAAGACCCTRTG...GGGATAACAGCGCAATCC" \
  --p-front-r "GGATTGCGCTGTTATCCC...CAYAGGGTCTTCTCGTCT" \
  --p-error-rate 0.1 \
  --p-overlap 3 \
  --p-discard-untrimmed \
  --p-cores 4 \
  --o-trimmed-sequences trimmed-seqs-linked.qza \
  --verbose

My reasoning: joining the 5' primer and 3' read-through with ... on --p-front-f/--p-front-r makes the 5' component the required part of a linked adapter, so a read is only marked "trimmed" if the primer was found — and --p-discard-untrimmed then discards any pair lacking the primer, while the optional 3' component still strips the read-through in the same pass. I've dropped --p-adapter-f/--p-adapter-r since both ends now live inside the front strings, and left --p-times at 1.

My questions:

  1. Is switching to linked adapters the correct and recommended fix for this primer-retention issue, and is my explanation of the separate-adapter behaviour accurate?
  2. In the QIIME2 wrapper, is the 5' component of a linked adapter defined via --p-front-f treated as required by default (so --p-discard-untrimmed enforces primer presence)? I want to be sure the required/optional default is what I expect.
  3. Is the 5' component anchored to the read start by default, or should I prepend ^ (e.g. ^AGACGAGAAGACCCTRTG...) to force anchoring?
  4. Anything else I should verify — e.g. is re-running the --action=none scan on the new output (expecting ~0% primer retention) a sound way to confirm the fix?

Thanks very much for any guidance!

Hello @bioinfo_rookie,

  1. Yes, I think trying the linked adapters is a good idea; however, I believe you would want to use --p-adapter-f and --p-adapter-r to define your linked primers.
  2. The --p-front-f parameter is not required
  3. Append $ to force anchoring on reverse reads. Prepend ^ to force anchoring on forward reads.
  4. I think your method of verification is reasonable; however, if you are going to anchor the primers in your QIIME 2 command, you should also anchor them in the raw cutadapt command (assuming it supports anchoring)

EDIT: I typoed the ^ and $ and put them backwards before. I fixed that, but I'm leaving this note here in case someone read the unedited version and was confused