# How to check of a channel is empty?

**URL:** <https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690>\
**Category:** Ask for help\
**Created:** [April 24, 2024, 9:02am UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690 "2024-04-24T09:02:47Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![bhanu\_gandham](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/bhanu_gandham/32/648_2.png) [@bhanu\_gandham](https://community.seqera.io/u/bhanu_gandham)\
**Post date:** [April 24, 2024, 9:02am UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/1 "2024-04-24T09:02:47Z")

</div>

I want to check if the channel output of a process is empty. Here is my script:

```auto
process PREPROCESS_FASTQ {

    publishDir "${params.workDir}" , mode: 'copy'
    beforeScript 'chmod o+rw .'

    input:
    tuple val(sample_id), val(order_id), path(fastqs), path(frum_fastqs)

    output:
    tuple val(sample_id), val(order_id), path("${sample_id}_a_all.fastq.gz"), path(frum_fastqs), emit: reuse
    tuple val(sample_id), val(order_id), path("${sample_id}_a_all.fastq.gz"), emit: noreuse
    val(frum_fastqs), emit: check

    script:
    """
    zcat ${fastqs} | gzip > ${sample_id}_a_all.fastq.gz
    """
}
workflow {
    combined_fastq = PREPROCESS_FASTQ(frum_files)
    if(combined_fastq.check.ifEmpty(true))
    {
        combined_fastq.reuse.view() 
    }
    else{
        combined_fastq.noreuse.view()
    }
}

```

Here is my samplesheet:

```auto
sample,samplename,orderid,fastq_dir,reference,frum_fastq_dir
sample01_run1,sample01,ord_01,/sample01/b03/*.fastq.gz,,
sample02_run1,sample02,ord_02,/sample02/b03/*.fastq.gz,,/fastq_pass/b01/*fastq.gz

```

For the first row in the samplesheet, I want the script to generate “combined\_fastq.noreuse.view()” and for the second row of the samplesheet, generate “combined\_fastq.reuse.view()”. How do i do this?

---

<div class="post-metadata">

**Author:** ![Adam\_Talbot](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/adam_talbot/32/62_2.png) [@Adam\_Talbot](https://community.seqera.io/u/Adam_Talbot)\
**Post date:** [April 24, 2024, 10:22am UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/2 "2024-04-24T10:22:55Z")

</div>

There’s an important concept here, you need to check to be operating on the contents of a channel, not the channel itself. Let me explain…

When you do `if(combined_fastq.check.ifEmpty(true))` you are saying the following:

> if the channel `combined_fastq.check` is empty, view the reuse channel

But this doesn’t really make sense, because a channel is an object. It’s a way of chaining processes together, so when you check it you are saying “hey, does this channel contain anything?”, but of course the channel does contain stuff, because you just populated it from the process. If you check the documentation for the [ifEmpty](https://www.nextflow.io/docs/latest/operator.html#ifempty) operator, you will see it creates a channel when the channel is empty, so your example code is creating a new channel containing the value `true` within the `if` statement, instead of filtering on a criteria. Darn!

What you want to do is check the _contents_ of the channel, to see if it contains the item contain `frum_fastq`. If we rephrase your question slighty…

> if items in the channel `combined_fastq.reuse` contains `frum_fastqs`, view them

This now becomes more clear what to do. We should look inside the items within the `combined_fastq` outputs and see if they include `frum_fastqs`.

Based on your samplesheet, we can actually do this without running a process at all! Let’s have a go. I’ve saved your example samplesheet into a file `input.csv`.

```auto
workflow {
    samplesheet_ch = Channel.fromPath("input.csv", checkIfExists: true)
        .splitCsv(header: true) // Split the CSV file into individual items

    // Let's get only the samples that have a valid value for frum_fastq_dir 
    samplesheet_ch
        .filter { it.frum_fastq_dir }
        .view()
}

```

This should write the following to your terminal:

```auto
> nextflow run .
N E X T F L O W ~ version 23.10.1
Launching `./main.nf` [chaotic_cray] DSL2 - revision: 62eb8c2da7
[sample:sample02_run1, samplename:sample02, orderid:ord_02, fastq_dir:/sample02/b03/*.fastq.gz, reference:, frum_fastq_dir:/fastq_pass/b01/*fastq.gz]

```

The first part is reading the samplesheet and parsing it using the [splitCsv](https://www.nextflow.io/docs/latest/operator.html#splitcsv) operator.

The second part uses [filter](https://www.nextflow.io/docs/latest/operator.html#filter) to remove any samples from the channel that _do not_ contain a value for `frum_fastq_dir`. This leaves us with a single sample for `frum_fastq`.

So how can we use this? Well it depends on exactly what you want to do, but let’s imagine you want to run PREPROCESS\_FASTQS on samples that do not contain `frum_fastqs`. We could do this:

```auto
process PREPROCESS_FASTQ {

    input:
    tuple val(sample_id), val(order_id), path(fastqs)

    output:
    tuple val(sample_id), val(order_id), path("${sample_id}_a_all.fastq.gz")

    script:
    """
    echo "myfastqdatagoeshere" | gzip > ${sample_id}_a_all.fastq.gz
    """
}
workflow {
    samplesheet_ch = Channel.fromPath("input.csv", checkIfExists: true)
        .splitCsv(header: true) // Split the CSV file into individual items

    samplesheet_ch
        // Let's remove samples that do not include frum_fastq_dir
        .filter { !it.frum_fastq_dir }
        // We use a map to make the channel fit the input tuple of the process
        .map { meta ->
            tuple(meta.sample_id, meta.order_id, file(meta.fastq_dir, checkIfExists: true))
        }
        .set { for_preprocessing_ch }

    for_preprocessing_ch.view() // I put this here for debugging. It can be removed.
    PREPROCESS_FASTQ(for_preprocessing_ch)
}

```

In conclusion, it’s possible to check if a channel is empty using isEmpty, however, I’m not sure this is what you want to achieve. Instead, you have to think about operating on the contents of your channels and using them to connect your processes together and build your pipeline. I hope this helps!

---

<div class="post-metadata">

**Author:** ![bhanu\_gandham](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/bhanu_gandham/32/648_2.png) [@bhanu\_gandham](https://community.seqera.io/u/bhanu_gandham)\
**Post date:** [April 24, 2024, 4:03pm UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/3 "2024-04-24T16:03:04Z")

</div>

this is very helpful, thank you @Adam_Talbot !!

---

<div class="post-metadata">

**Author:** ![bhanu\_gandham](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/bhanu_gandham/32/648_2.png) [@bhanu\_gandham](https://community.seqera.io/u/bhanu_gandham)\
**Post date:** [April 24, 2024, 9:45pm UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/4 "2024-04-24T21:45:02Z")

</div>

HI @Adam_Talbot I have a follow up question.

This is essentially the pseudocode of what I am trying to do:

> channel\_1 = Channel.fromPath(params.samplesheet)  
> .splitCsv(header: true)  
> .filter {it.frum\_fastq\_dir}

> channel\_2 = Channel.fromPath(params.samplesheet)  
> .splitCsv(header: true)  
> .filter {!it.frum\_fastq\_dir}

> if(channel\_1){  
> channel\_3 = processA(channel\_1)  
> }

> else if(channel\_2){  
> channel\_3 = processB(channel\_2)  
> }

> processC(channel\_3)

What i am trying to do here is, if frum\_fastq\_dir column in the samplesheet has values, a) create channel\_1 if no values in frum\_fastq\_dir column which then is used in processA, b) then create channel\_2 which is used in processB and c) i want to create a third processC that takes channel\_3 as input, which is that collected from the output of process A or B.

The implementation of this logic doesn’t work because even if the channel\_1 or channel\_2 are empty, they still exist and the if and else if statements are both true. So how do i implement this logic in nextflow?

---

<div class="post-metadata">

**Author:** ![Adam\_Talbot](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/adam_talbot/32/62_2.png) [@Adam\_Talbot](https://community.seqera.io/u/Adam_Talbot)\
**Post date:** [April 25, 2024, 8:40am UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/5 "2024-04-25T08:40:11Z")

</div>

> [@bhanu\_gandham](#):
>
> The implementation of this logic doesn’t work because even if the channel\_1 or channel\_2 are empty, they still exist and the if and else if statements are both true. So how do i implement this logic in nextflow?

Remember, you are checking the _contents_ of the channels, not the channels themselves.

But there’s something else you need to consider. If a channel is empty, Nextflow will not run a process! In that way, we don’t need to use an if statement at all!

In this example, I use a branch operator to split the channel into two (this is basically like two filter operators together). Then I run PROCESS\_A and PROCESS\_B on the channels. Afterwards, I mix the results of both channels so that they are concatenated together. If you play with the input samplesheet, you will note that the executed processes change based on channel contents. You have your conditional logic defined in your pipeline structure, no if statements in sight!

```nextflow
process PROCESS_A {
    input:
        val frum_fastq

    output:
        val frum_fastq

    script:
    """
    echo $frum_fastq
    """
}

process PROCESS_B {
    input:
        val frum_fastq

    output:
        val frum_fastq

    script:
    """
    echo $frum_fastq
    """
}

process PROCESS_C {
    input:
        val frum_fastq

    output:
        val frum_fastq

    script:
    """
    echo $frum_fastq
    """
}

workflow {
    samplesheet_ch = Channel.fromPath("input.csv", checkIfExists: true)
        .splitCsv(header: true) // Split the CSV file into individual items

    samplesheet_ch
        // Split samples into with frum_fastq_dir and without frum_fastq_dir
        .branch { 
            frum_fastq: it.frum_fastq_dir
            no_frum_fastq: !it.frum_fastq_dir 
        }
        .set { for_preprocessing_ch }

    // Execute each process independently
    process_a_out = PROCESS_A(for_preprocessing_ch.frum_fastq)
    process_b_out = PROCESS_B(for_preprocessing_ch.no_frum_fastq)

    // Get the results back together
    results = process_a_out.mix(process_b_out)
    process_c_out = PROCESS_C(results)
    process_c_out.view()
}

```

---

<div class="post-metadata">

**Author:** ![bhanu\_gandham](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/bhanu_gandham/32/648_2.png) [@bhanu\_gandham](https://community.seqera.io/u/bhanu_gandham)\
**Post date:** [April 25, 2024, 11:29am UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/6 "2024-04-25T11:29:50Z")

</div>

i tried that and this is the error i get: Multi-channel output cannot be applied to operator mix for which argument is already provided

---

<div class="post-metadata">

**Author:** ![Adam\_Talbot](https://dub1.discourse-cdn.com/flex013/user_avatar/community.seqera.io/adam_talbot/32/62_2.png) [@Adam\_Talbot](https://community.seqera.io/u/Adam_Talbot)\
**Post date:** [April 25, 2024, 12:04pm UTC](https://community.seqera.io/t/how-to-check-of-a-channel-is-empty/690/7 "2024-04-25T12:04:50Z")

</div>

You need to make sure you apply to the split channel, like so:

```auto
for_preprocessing_ch.frum_fastq.mix(etc) // THIS
for_preprocessing_ch // NOT THIS

```

Or, if you are dealing with the outputs of a process make sure you do it on the contents of `out`. For example:

```auto
PROCESS_A.out.frum_fastq // THIS
PROCESS_A.out // NOT THIS

```
