Skip to content

Topic channels with .command.* files fail in GCP Batch environment in Nextflow 25.x #6213

Open
@regan-hayward

Description

@regan-hayward

Bug report

Expected behavior and actual behavior

I'm currently using a custom pipeline with Nextflow v24.04.2 that includes topic channels using three of the .command files.

For example:

output:
tuple val(task.process), val(task.tag), path('.command.err'), emit: nf_stderr, topic: 'command_errors'
tuple val(task.process), val(task.tag), path('.command.sh'), emit: nf_script, topic: 'command_script'
tuple val(task.process), val(task.tag), path('.command.out'), emit: nf_stdout, topic: 'command_stdout'

This code works fine in v24, but when updating to v25, I get the following error:

***** Error report *****
Error executing process > 'HELLO_WORLD_DOCKER (Test)'

Caused by:
  java.lang.RuntimeException: 


Command executed:

  echo "hello world"

Command exit status:
  1

Command output:
  hello worldmv: '.command.sh' and '/mnt/disks/nextflow-workspace./.command.sh' are the same filecp: cannot stat '.command.out': No such file or directorycp: cannot stat '.command.err': No such file or directory

Steps to reproduce the problem

An example of this process:

process HELLO_WORLD_DOCKER {
    tag "$meta.id"
    label 'process_single'
    container "test_docker"

    input:
    tuple val(meta), path(r1), path(r2)

    output:
    tuple val(task.process), val(task.tag), path('.command.err'), emit: nf_stderr, topic: 'command_errors'
    tuple val(task.process), val(task.tag), path('.command.sh'), emit: nf_script, topic: 'command_script'
    tuple val(task.process), val(task.tag), path('.command.out'), emit: nf_stdout, topic: 'command_stdout'

    when:
    task.ext.when == null || task.ext.when

    script:
    """
    echo "hello world"
    """
}

Environment

The runtime environment:

  • Local: Ubuntu 24.04.2 LTS
  • Running local Nextflow head job with gcp-batch profile
  • Ubuntu 22.04 docker container

Have tried the following versions which result in the same error:

  • Nextflow: 25.04.2, 25.04.4 and 25.05.0-edge
  • nf-google plugin: 1.21.0 and 1.22.0

Additional context

To narrow the issue down, I created a mock local example, which does run.

nextflow.enable.dsl=2

process DEMO_TOPICS {
    container 'nextflow-test:latest'

    output:
    tuple val(task.process), val(task.tag), path('.command.err'), emit: nf_stderr, topic: 'command_errors'
    tuple val(task.process), val(task.tag), path('.command.sh'), emit: nf_script, topic: 'command_script'
    tuple val(task.process), val(task.tag), path('.command.out'), emit: nf_stdout, topic: 'command_stdout'

    script:
    """
    echo "Hello world"
    """
}

workflow {
    // Collect from the topic channels
    Channel.topic('command_errors').view { process, tag, file -> "ERROR from $process: ${file.text}" }
    Channel.topic('command_script').view { process, tag, file -> "SCRIPT from $process: ${file.text.trim().split('\n')[0]}" }
    Channel.topic('command_stdout').view { process, tag, file -> "OUTPUT from $process: ${file.text}" }
    
    DEMO_TOPICS()
}

So the issue would appear to be specifically linked to using GCP and accessing the .command files.

Suspecting this, I tried using afterScript, but the same issue occurred.
I've tried a bunch of somewhat related flags and options, including the following - but didn't resolve the issue:

  • Making the outputs optional: path('.command.err', optional = true)
  • Adding wildcards: ??.command.err
  • Different stage-outs: StageOutMode 'copy', 'move'
  • Don't follow symlinks when copying: mode: 'copyNoFollow'
  • Relative/absolute symlinks: mode: 'rellink', 'symlink'
  • Enabled scratch: scratch true

Possible cause:

It appears that in Nextflow 25.x, there's a race condition or change in how .command.* files are handled when used with topic channels in the GCP Batch environment. The error suggests that the files are being accessed simultaneously by different parts of the Nextflow execution system, or that there's a timing issue between when the files are created/staged and when the topic channels try to access them.

Workaround

There is a workaround for anyone else in the same situation, but it would be nice to be able to use the .command files directly.

output:
tuple val(task.process), val(task.tag), path('cmd.err'), emit: nf_stderr, topic: 'command_errors'
tuple val(task.process), val(task.tag), path('cmd.sh'), emit: nf_script, topic: 'command_script'
tuple val(task.process), val(task.tag), path('cmd.out'), emit: nf_stdout, topic: 'command_stdout'

script:
"""
echo "hello world" > cmd.out 2> cmd.err
cp .command.sh cmd.sh || echo "Script not available" > cmd.sh
"""

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions