This is a test version of Biostars. For the public version, visit https://www.biostars.org.
MACS2 “0 reads have been read” error after alignmentSieve in ATAC-seq Nextflow pipeline (single-end)

Hi all,

I am developing an ATAC-seq analysis pipeline for single-end reads using Nextflow and am running into an error at the peak calling step with MACS2.

The error is:

ERROR ~ Error executing process > 'CALL_PEAKS (2)'

Caused by:
  Process `CALL_PEAKS (2)` terminated with an error exit status (1)
...
  Command output:
    0

  Command error:
    INFO  ...: #1  total tags in treatment: 0
    ...
    ZeroDivisionError: float division by zero

My pipeline is:

  1. Download with SRA tools. Do QC with FastQC, trimmomatic, MultiQC, and samtools flagstat.
  2. Alignment using Bowtie2 for single end reads
  3. Remove mitochondrial reads with grep
  4. Blacklist removal with bedtools intersect -v
  5. Tn5 shift correction using alignmentSieve
  6. MACS2 peak calling, using callpeak with -f BAM --nomodel --extsize 147 for single-end ATAC-seq

The reference genome is mm10/GRCm38.

The relevant part of the workflow is:

REMOVE_BLACKLIST(BOWTIE2_ALIGN.out.filtered_bam, params.blacklist)
    SHIFT_ALIGN(REMOVE_BLACKLIST.out)
    CALL_PEAKS(SHIFT_ALIGN.out)

The relevant processes are:

process REMOVE_BLACKLIST {
    conda 'envs/bedtools_env.yml'

    input:
    tuple val(run), val(biosample), val(samplename), val(library_layout), val(library_source), val(experiment), path(filtered_bam), path(filtered_index)
    path blacklist

    output:
    tuple val(run), val(biosample), val(samplename), val(library_layout), val(library_source), val(experiment), path("${run}.blacklist_removed.sorted.bam"),  path("${run}.blacklist_removed.sorted.bam.bai")

    script:
    """
    bedtools intersect -v -abam ${filtered_bam} -b ${blacklist} > ${run}.blacklist_removed.bam

    # Sort & index the new BAM
    samtools sort -o ${run}.blacklist_removed.sorted.bam ${run}.blacklist_removed.bam
    samtools index ${run}.blacklist_removed.sorted.bam
    rm ${run}.blacklist_removed.bam
    samtools view -c ${run}.blacklist_removed.sorted.bam
    """
}

process SHIFT_ALIGN {
    conda 'envs/deeptools_env.yml'

    input:
    tuple val(run), val(biosample), val(samplename), val(library_layout), val(library_source), val(experiment), path(filtered_bam), path(filtered_index)

    output:
    tuple val(run), val(biosample), val(samplename), val(library_layout), val(library_source), val(experiment), path("${run}_shifted.bam"), path("${run}_shifted.bam.bai")

    script:
    """
    alignmentSieve -b ${filtered_bam} -o ${run}_shifted.bam  --ATACshift --minMappingQuality 10 --filterMetrics log.txt
    samtools index ${run}_shifted.bam
    """
}

process CALL_PEAKS {
    conda 'envs/macs2_env.yml'
    publishDir params.outdir, mode: "copy", pattern: ['*.narrowPeak','*.bed','*.xls','*.bdg']

    input:
    tuple val(run), val(biosample), val(samplename), val(library_layout), val(library_source), val(experiment), path(shifted_blacklist_removed_bam),  path(shifted_blacklist_removed_bam_index)

    output:
    tuple val(run), val(biosample), val(samplename), val(library_layout), val(library_source), val(experiment),
          path("${run}_peaks.narrowPeak"),
          path("${run}_summits.bed"),
          path("${run}_peaks.xls"),
          path("${run}_treat_pileup.bdg")

    script:
    """
    samtools view -c ${shifted_blacklist_removed_bam}
    macs2 callpeak \
        -t ${shifted_blacklist_removed_bam} \
        -f BAM \
        -g mm \
        --nomodel \
        --keep-dup auto \
        --extsize 147 \
        -n ${run}
    """
}

My package versions are:

deeptools=3.5.6
samtools=1.20
macs2=2.2.9.1
bedtools=2.31.1

I have narrowed down the problem to alignmentSieve when trying to apply the ATAC-seq shift. Output BAM files from the remove blacklist process have millions of reads, but the input BAM files to the call peaks process appear to have 0 reads. The result is when I try to call MACS2, MACS2 sees the input BAM files have 0 reads.

I am not sure why alignmentSieve outputs BAM files with 0 reads. I checked the documentation, and inputs/outputs between processes seem to line up.

deeptools nextflow atac-seq macs2

Can you share the log.txt file from the alignmentSieve output?

Hi, Arup.

Thank you for commenting. Here are the log.txt files for the samples that made it through alignmentSieve:

#bamFilterReads --filterMetrics
#File   Reads Remaining Total Initial Reads
SRR28895189.blacklist_removed.sorted.bam    16426157    16426157

#bamFilterReads --filterMetrics
#File   Reads Remaining Total Initial Reads
SRR28895183.blacklist_removed.sorted.bam    19213873    19213873

#bamFilterReads --filterMetrics
#File   Reads Remaining Total Initial Reads
SRR28895185.blacklist_removed.sorted.bam    18051712    18051712

#bamFilterReads --filterMetrics
#File   Reads Remaining Total Initial Reads
SRR28895190.blacklist_removed.sorted.bam    22398163    22398163

So, it does look like alignmentSieve still does produce BAM files with reads.

Manually inspect the bam files whether they have content. If so, run the peak calling manually outside of nextflow to debug. Do that for the troublesome sample and post the full logs. Debugging should be always from most lowlevel (manual execution) to most highlevel (inside wrappers/cotnainers/workflow managers).

Hi, ATpoint.

I checked the header. This is what the header in the work directory of the call peak process looks like for one BAM file:

@HD     VN:1.5  SO:coordinate
@SQ     SN:chr1 LN:195471971
@SQ     SN:chr10        LN:130694993
@SQ     SN:chr11        LN:122082543
@SQ     SN:chr12        LN:120129022
@SQ     SN:chr13        LN:120421639
@SQ     SN:chr14        LN:124902244
@SQ     SN:chr15        LN:104043685
@SQ     SN:chr16        LN:98207768
@SQ     SN:chr17        LN:94987271
@SQ     SN:chr18        LN:90702639
@SQ     SN:chr19        LN:61431566
@SQ     SN:chr1_GL456210_random LN:169725
@SQ     SN:chr1_GL456211_random LN:241735
@SQ     SN:chr1_GL456212_random LN:153618
@SQ     SN:chr1_GL456213_random LN:39340
@SQ     SN:chr1_GL456221_random LN:206961
@SQ     SN:chr2 LN:182113224
@SQ     SN:chr3 LN:160039680
@SQ     SN:chr4 LN:156508116
@SQ     SN:chr4_GL456216_random LN:66673
@SQ     SN:chr4_JH584292_random LN:14945
@SQ     SN:chr4_GL456350_random LN:227966
@SQ     SN:chr4_JH584293_random LN:207968
@SQ     SN:chr4_JH584294_random LN:191905
@SQ     SN:chr4_JH584295_random LN:1976
@SQ     SN:chr5 LN:151834684
@SQ     SN:chr5_JH584296_random LN:199368
@SQ     SN:chr5_JH584297_random LN:205776
@SQ     SN:chr5_JH584298_random LN:184189
@SQ     SN:chr5_GL456354_random LN:195993
@SQ     SN:chr5_JH584299_random LN:953012
@SQ     SN:chr6 LN:149736546
@SQ     SN:chr7 LN:145441459
@SQ     SN:chr7_GL456219_random LN:175968
@SQ     SN:chr8 LN:129401213
@SQ     SN:chr9 LN:124595110
@SQ     SN:chrX LN:171031299
@SQ     SN:chrX_GL456233_random LN:336933
@SQ     SN:chrY LN:91744698
@SQ     SN:chrY_JH584300_random LN:182347
@SQ     SN:chrY_JH584301_random LN:259875
@SQ     SN:chrY_JH584302_random LN:155838
@SQ     SN:chrY_JH584303_random LN:158099
@SQ     SN:chrUn_GL456239       LN:40056
@SQ     SN:chrUn_GL456367       LN:42057
@SQ     SN:chrUn_GL456378       LN:31602
@SQ     SN:chrUn_GL456381       LN:25871
@SQ     SN:chrUn_GL456382       LN:23158
@SQ     SN:chrUn_GL456383       LN:38659
@SQ     SN:chrUn_GL456385       LN:35240
@SQ     SN:chrUn_GL456390       LN:24668
@SQ     SN:chrUn_GL456392       LN:23629
@SQ     SN:chrUn_GL456393       LN:55711
@SQ     SN:chrUn_GL456394       LN:24323
@SQ     SN:chrUn_GL456359       LN:22974
@SQ     SN:chrUn_GL456360       LN:31704
@SQ     SN:chrUn_GL456396       LN:21240
@SQ     SN:chrUn_GL456372       LN:28664
@SQ     SN:chrUn_GL456387       LN:24685
@SQ     SN:chrUn_GL456389       LN:28772
@SQ     SN:chrUn_GL456370       LN:26764
@SQ     SN:chrUn_GL456379       LN:72385
@SQ     SN:chrUn_GL456366       LN:47073
@SQ     SN:chrUn_GL456368       LN:20208
@SQ     SN:chrUn_JH584304       LN:114452
@PG     ID:bowtie2      PN:bowtie2      VN:2.5.4        CL:"/work/conda/env-f6c124b3dfc835a5-bd7effcc2059eb64ec0c99e020db6456/bin/bowtie2-align-s --wrapper basic-0 -x bowtie2_index/mm10 -S SRR28895188.sam --very-sensitive -p 16 -q -U SRR28895188_trimmed.fastq.gz"
@PG     ID:samtools     PN:samtools     PP:bowtie2      VN:1.20 CL:samtools view -q 30 -F 4 -b SRR28895188.sam
@PG     ID:samtools.1   PN:samtools     PP:samtools     VN:1.20 CL:samtools sort -o SRR28895188.sorted.bam SRR28895188.bam
@PG     ID:samtools.2   PN:samtools     PP:samtools.1   VN:1.20 CL:samtools view -h SRR28895188.sorted.bam
@PG     ID:samtools.3   PN:samtools     PP:samtools.2   VN:1.20 CL:samtools view -bS
@PG     ID:samtools.4   PN:samtools     PP:samtools.3   VN:1.21 (pysam

I also tried running call peaks outside of the nextflow pipeline, and I still run into the same error:

# Command line: callpeak -t SRR28895188_shifted.bam -f BAM -g mm --nomodel --keep-dup auto --extsize 147 -n SRR28895183
# ARGUMENTS LIST:
# name = SRR28895183
# format = BAM
# ChIP-seq file = ['SRR28895188_shifted.bam']
# control file = None
# effective genome size = 1.87e+09
# band width = 300
# model fold = [5, 50]
# qvalue cutoff = 5.00e-02
# The maximum gap between significant sites is assigned as the read length/tag size.
# The minimum length of peaks is assigned as the predicted fragment length "d".
# Larger dataset will be scaled towards smaller dataset.
# Range for calculating regional lambda is: 10000 bps
# Broad region calling is off
# Paired-End mode is off

INFO  @ Mon, 08 Dec 2025 12:40:35: #1 read tag files... 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1 read treatment tags... 
struct.error: unpack requires a buffer of 4 bytes
Exception ignored in: 'MACS2.IO.Parser.BAMParser.tsize'
Traceback (most recent call last):
  File "/macs2_env/lib/python3.11/site-packages/MACS2/callpeak_cmd.py", line 389, in load_tag_files_options
    ttsize = tp.tsize()
             ^^^^^^^^^^
struct.error: unpack requires a buffer of 4 bytes
INFO  @ Mon, 08 Dec 2025 12:40:35: 0 reads have been read. 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1 tag size is determined as 0 bps 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1 tag size = 0.0 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1  total tags in treatment: 0 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1 calculate max duplicate tags in single position based on binomial distribution... 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1  max_dup_tags based on binomial = 0 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1 filter out redundant tags at the same location and the same strand by allowing at most 0 tag(s) 
INFO  @ Mon, 08 Dec 2025 12:40:35: #1  tags after filtering in treatment: 0 
ZeroDivisionError: float division by zero

I have also tried removing the blacklist after shifting alignments and calling peaks, but I still run into the same Zero Division error with calling peaks.

In terms of removing the blacklist after shifting alignments, this was the workflow:

SHIFT_ALIGN(BOWTIE2_ALIGN.out.filtered_bam)
    CALL_PEAKS(SHIFT_ALIGN.out)
    REMOVE_BLACKLIST(CALL_PEAKS.out, params.blacklist)
> INFO  @ Mon, 08 Dec 2025 12:40:35: 0 reads have been read. 

The bam file is empty. Now you have to dig back why. Is it the alignment that failed, or any filtering or the sieving.

I figured out the problem and it was --ATACshift and alignmentSieve. According to the documentation,

If the --shift or --ATACshift options are used, then only properly-paired reads will be used.

--ATACshift does not work on single end reads. alignmentSieve documents read statistics before filtering, which is confusing.

The alignmentSieve step is definitely generating a BAM file. I would suggest looking into the corresponding work directory of the run.

1 answer

If the --shift or --ATACshift options are used, then only properly-paired reads will be used.

--ATACshift does not work on single end reads. The solution may be to forego shifting the alignments.

Log in to answer this question.