Answers.Body: <p>Channel names must consist only alphanumeric characters including underscores. Your channel called 'plink-data' contains a hyphen. This is problematic because it is interpreted as a minus() operation to remove 'data' from 'plink'. You get a NullPointerException since 'plink' hasn't been defined. You can test this easily with the following example:</p>
  <pre><code>Channel
      .of(1..23, 'X', 'Y')
      .set { chr-names }
  
  chr-names.view()
  </code></pre>
  <p>Results:</p>
  <pre><code>Cannot invoke method minus() on null object
  </code></pre>
  <p>The solution is to just use an underscore instead of a hyphen:</p>
  <pre><code>Channel
      .of(1..23, 'X', 'Y')
      .set { chr_names }
  
  chr_names.view()
  </code></pre>
  <hr />
  <p><strong>Follow-up issues:</strong></p>
  <p>I think if you want to use the bfiles plink option (and I think this is reasonable), I think it makes the most sense to just keep your bfiles in a tuple:</p>
  <pre><code>Channel
      .fromFilePairs( &quot;${params.input_dir}/*.{bed,bim,fam}&quot;, size: 3 )
      .set { plink_data }
  
  
  process test1{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bfiles) from plink_data
  
      output:
      tuple val(&quot;<span class="math-container">${sample_name}-t1"), path("$</span>{sample_name}-t1.{bed,bim,fam}&quot;) into test1_results
  
      &quot;&quot;&quot;
      plink \\
          --bfile &quot;<span class="math-container">${sample_name}" \\
          --maf 0.05 \\
          --make-bed \\
          --out "$</span>{sample_name}-t1&quot;
      &quot;&quot;&quot;
  }
  
  process test2{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bfiles) from test1_results
  
      output:
      tuple val(&quot;<span class="math-container">${sample_name}-t2"), path("$</span>{sample_name}-t2.{bed,bim,fam}&quot;) into test2_results
  
      &quot;&quot;&quot;
      plink \\
          --bfile &quot;<span class="math-container">${sample_name}" \\
          --maf 0.01 \\
          --make-bed \\
          --out "$</span>{sample_name}-t2&quot;
      &quot;&quot;&quot;
  }
  </code></pre>
  <p>If you need to reference each bfile separately, you could just unpack the tuple and reference each file accordingly:</p>
  <pre><code>Channel
      .fromFilePairs( &quot;${params.input_dir}/*.{bed,bim,fam}&quot;, size: 3 )
      .map { group_key, files -&gt; tuple( group_key, *files ) }
      .set { plink_data }
  
  
  process test1{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bed), path(bim), path(fam) from plink_data
  
      output:
      tuple val(&quot;<span class="math-container">${sample_name}-t1"), path("$</span>{sample_name}-t1.{bed,bim,fam}&quot;) into test1_results
  
      &quot;&quot;&quot;
      plink \\
          --bed &quot;<span class="math-container">${bed}" \\
          --bim "$</span>{bim}&quot; \\
          --fam &quot;<span class="math-container">${fam}" \\
          --maf 0.05 \\
          --make-bed \\
          --out "$</span>{sample_name}-t1&quot;
      &quot;&quot;&quot;
  }
  
  process test2{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bed), path(bim), path(fam) from test1_results
  
      output:
      tuple val(&quot;<span class="math-container">${sample_name}-t2"), path("$</span>{sample_name}-t2.{bed,bim,fam}&quot;) into test2_results
  
      &quot;&quot;&quot;
      plink \\
          --bed &quot;<span class="math-container">${bed}" \\
          --bim "$</span>{bim}&quot; \\
          --fam &quot;<span class="math-container">${fam}" \\
          --maf 0.01 \\
          --make-bed \\
          --out "$</span>{sample_name}-t2&quot;
      &quot;&quot;&quot;
  }
  </code></pre>
  <p>Note that in the first example, <code>bfiles</code> could be replaced with <code>&quot;*&quot;</code> since no reference is made to the tuple of bfiles anyway. Also note that the list of files produced using the <a href="https://www.nextflow.io/docs/latest/channel.html#fromfilepairs" rel="nofollow noreferrer">fromFilesPairs operator</a> are returned in lexicographic order.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-19T16:50:31.367Z
Answers.Text: Thanks @Steve, I modified the code but getting a new issue:
  'process test1{
  publishDir params.publish
  input:
  set t1, file(plk1) from data
  output: set t2, file "${t2}.{bed,fam.bim}" into test1_results
  script:
  """
  plink --bfile $t1 --maf 0.05 --make-bed --out ${t2}
  """
  '
  the error is: no such variable: t2
  I have 3 files (.bed,.bim,.fam), process test1 will generate another 3 (.bed,.bim,.fam) files which will be used in the next process.
  How could I declare t1,t2,t3 etc (the inputs and outputs) correctly?
Answers.UserDisplayName: zillur rahman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T03:28:07.933Z
Answers.Text: No worries @zillurrahman, I have added some example code to show how you could declare your inputs and outputs. The inputs could just be a tuple of bfiles or each file could be referenced separately. I haven't used plink before and have only had a (very) quick read of the docs, so there may be some more issues. Hopefully it's enough to get you started.
Answers.UserDisplayName: Steve
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T09:35:06.340Z
Answers.Text: Thanks a lot @Steve. It works as I expected! One thing, plink also generate a log file, I need this as one of the outputs but the log will not be used in the next process. Now I am adding more processes in the script, I will get back to you if I got stuck again.
Answers.UserDisplayName: zillur rahman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T11:19:44.783Z
Answers.Text: So for Nextflow to be able to publish a file using the publishDir directive, it (the file) needs to be referenced in your process' output declaration block somehow. If it's not required by any downstream process, you can just add another output channel, for example: `path("${sample_name.log}") into test1_logs`. Please let me know if that doesn't make sense. Cheers.
Answers.UserDisplayName: Steve
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T11:57:13.890Z
Answers.Text: Thank you @Steve, It seems I can declare multiple output, which is very much useful for my pipeline. Just one thing, if I  'path("${sample_name.log}") into test1_logs' it shows 'No such variable: log'.
Answers.UserDisplayName: zillur rahman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T14:18:13.000Z
Answers.Text: Erp there's a typo in there.. you'll need: `path("${sample_name}.log") into test1_logs` if your log's filename fits that format. Whether it does or not, you'll need to check. HTH.
Answers.UserDisplayName: Steve
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T16:35:51.960Z
Answers.Text: Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/121077/discussion-between-zillur-rahman-and-steve).
Answers.UserDisplayName: zillur rahman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-20T17:26:35.150Z
Answers.Text: Thanks @Steve, I also tried it. If I use path("${sample_name}.log") , it shows error execution prosess; caused by missing output files. If I use path("${sample_name}".log) , it shows no such variable: log
Answers.UserDisplayName: zillur rahman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-21T03:09:00.397Z
Answers.Text: What's the name of your log file? I haven't run plink before, so I just used `"${sample_name}.log"` as an example. If the name of the log file is 'plink.log' then you'd use: `path("plink.log") into test1_logs` in your output declaration.
Answers.UserDisplayName: Steve
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-21T08:31:49.843Z
Answers.Text: Thanks @Steve, The final output.log is the log file. Sorry I failed to clarify. However, path("${sample_name}-t1.log") into test1_logs works as I expected! Thank a lot again.
Answers.UserDisplayName: zillur rahman
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-03-19T13:33:33.857Z
Answers.LastActivityDate: 2021-03-20T03:21:14.817Z
Answers.LastEditDate: 2021-03-20T03:21:14.817Z
Answers.UserDisplayName: Steve
Body: <p>Hi I was trying to use plink in nextflow and getting the error mentioned in the subject. Here is my code, any help what I am missing. I am new in nextflow, it was ok when input was a single file, but for grouped files, I am getting lost.</p>
  <pre><code>params.dir='data/'
  params.publish=&quot;output/&quot;
  Channel
  .fromFilePairs(&quot;${params.dir}*.{bed,fam,bim}&quot;,size:3){file -&gt; file.baseName}
  .set {plink-data}
      
  process test1{
  publishDir params.publish
  input:
  set t1,file(plk1) from plink-data
  output:
  file &quot;<span class="math-container">${t1}.{bed,fam,bim}" into test1_results
  script:
  output_file = "$</span>{t1}&quot;
  base = plk1[0].baseName
  &quot;&quot;&quot;
  module load plink
  plink --bfile <span class="math-container">$t1 --maf 0.05 --make-bed --out $</span>{output_file}
  &quot;&quot;&quot;
  }
  process test2{
  publishDir params.publish
  input:
  set file(bed), file(fam), file(bim) from test1_results.collect()
  output:
  set t2,file '<span class="math-container">${plk2}.{bed,fam,bim}' into test2_results
  script:
  output_file = "{t2}"
  base = plk2[0].baseName
  """
  plink --bfile $</span>t2 --maf 0.01 --make-bed --out ${output_file}
  &quot;&quot;&quot;
  }
  </code></pre>
  
Tags: <nextflow>
Title: Nextflow error: can not invoke method minus () on null object
ThreadText: # Nextflow error: can not invoke method minus () on null object
  
  (Asked by: username_0 on 2021-03-19)
  
  Hi I was trying to use plink in nextflow and getting the error mentioned in the subject. Here is my code, any help what I am missing. I am new in nextflow, it was ok when input was a single file, but for grouped files, I am getting lost.
  
  ```
  params.dir='data/'
  params.publish="output/"
  Channel
  .fromFilePairs("${params.dir}*.{bed,fam,bim}",size:3){file -> file.baseName}
  .set {plink-data}
      
  process test1{
  publishDir params.publish
  input:
  set t1,file(plk1) from plink-data
  output:
  file "${t1}.{bed,fam,bim}" into test1_results
  script:
  output_file = "${t1}"
  base = plk1[0].baseName
  """
  module load plink
  plink --bfile $t1 --maf 0.05 --make-bed --out ${output_file}
  """
  }
  process test2{
  publishDir params.publish
  input:
  set file(bed), file(fam), file(bim) from test1_results.collect()
  output:
  set t2,file '${plk2}.{bed,fam,bim}' into test2_results
  script:
  output_file = "{t2}"
  base = plk2[0].baseName
  """
  plink --bfile $t2 --maf 0.01 --make-bed --out ${output_file}
  """
  }
  
  ```
  
  **Tags:** nextflow
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2021-03-19. Score: 2 | Accepted answer
  
  Channel names must consist only alphanumeric characters including underscores. Your channel called 'plink-data' contains a hyphen. This is problematic because it is interpreted as a minus() operation to remove 'data' from 'plink'. You get a NullPointerException since 'plink' hasn't been defined. You can test this easily with the following example:
  
  ```
  Channel
      .of(1..23, 'X', 'Y')
      .set { chr-names }
  
  chr-names.view()
  
  ```
  
  Results:
  
  ```
  Cannot invoke method minus() on null object
  
  ```
  
  The solution is to just use an underscore instead of a hyphen:
  
  ```
  Channel
      .of(1..23, 'X', 'Y')
      .set { chr_names }
  
  chr_names.view()
  
  ```
  
  ---
  
  **Follow-up issues:**
  
  I think if you want to use the bfiles plink option (and I think this is reasonable), I think it makes the most sense to just keep your bfiles in a tuple:
  
  ```
  Channel
      .fromFilePairs( "${params.input_dir}/*.{bed,bim,fam}", size: 3 )
      .set { plink_data }
  
  process test1{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bfiles) from plink_data
  
      output:
      tuple val("${sample_name}-t1"), path("${sample_name}-t1.{bed,bim,fam}") into test1_results
  
      """
      plink \\
          --bfile "${sample_name}" \\
          --maf 0.05 \\
          --make-bed \\
          --out "${sample_name}-t1"
      """
  }
  
  process test2{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bfiles) from test1_results
  
      output:
      tuple val("${sample_name}-t2"), path("${sample_name}-t2.{bed,bim,fam}") into test2_results
  
      """
      plink \\
          --bfile "${sample_name}" \\
          --maf 0.01 \\
          --make-bed \\
          --out "${sample_name}-t2"
      """
  }
  
  ```
  
  If you need to reference each bfile separately, you could just unpack the tuple and reference each file accordingly:
  
  ```
  Channel
      .fromFilePairs( "${params.input_dir}/*.{bed,bim,fam}", size: 3 )
      .map { group_key, files -> tuple( group_key, *files ) }
      .set { plink_data }
  
  process test1{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bed), path(bim), path(fam) from plink_data
  
      output:
      tuple val("${sample_name}-t1"), path("${sample_name}-t1.{bed,bim,fam}") into test1_results
  
      """
      plink \\
          --bed "${bed}" \\
          --bim "${bim}" \\
          --fam "${fam}" \\
          --maf 0.05 \\
          --make-bed \\
          --out "${sample_name}-t1"
      """
  }
  
  process test2{
  
      publishDir params.publish_dir
  
      module 'plink'
  
      input:
      tuple val(sample_name), path(bed), path(bim), path(fam) from test1_results
  
      output:
      tuple val("${sample_name}-t2"), path("${sample_name}-t2.{bed,bim,fam}") into test2_results
  
      """
      plink \\
          --bed "${bed}" \\
          --bim "${bim}" \\
          --fam "${fam}" \\
          --maf 0.01 \\
          --make-bed \\
          --out "${sample_name}-t2"
      """
  }
  
  ```
  
  Note that in the first example, `bfiles` could be replaced with `"*"` since no reference is made to the tuple of bfiles anyway. Also note that the list of files produced using the [fromFilesPairs operator](https://www.nextflow.io/docs/latest/channel.html#fromfilepairs) are returned in lexicographic order.
  
  > **Comments:**
  > **username_0**: Thanks @username_1, I modified the code but getting a new issue: 'process test1{ publishDir params.publish input: set t1, file(plk1) from data output: set t2, file "${t2}.{bed,fam.bim}" into test1_results script: """ plink --bfile $t1 --maf 0.05 --make-bed --out ${t2} """ ' the error is: no such variable: t2 I have 3 files (.bed,.bim,.fam), process test1 will generate another 3 (.bed,.bim,.fam) files which will be used in the next process. How could I declare t1,t2,t3 etc (the inputs and outputs) correctly?  
  > **username_1**: No worries @username_0, I have added some example code to show how you could declare your inputs and outputs. The inputs could just be a tuple of bfiles or each file could be referenced separately. I haven't used plink before and have only had a (very) quick read of the docs, so there may be some more issues. Hopefully it's enough to get you started.  
  > **username_0**: Thanks a lot @username_1. It works as I expected! One thing, plink also generate a log file, I need this as one of the outputs but the log will not be used in the next process. Now I am adding more processes in the script, I will get back to you if I got stuck again.  
  > **username_1**: So for Nextflow to be able to publish a file using the publishDir directive, it (the file) needs to be referenced in your process' output declaration block somehow. If it's not required by any downstream process, you can just add another output channel, for example: `path("${sample_name.log}") into test1_logs`. Please let me know if that doesn't make sense. Cheers.  
  > **username_0**: Thank you @username_1, It seems I can declare multiple output, which is very much useful for my pipeline. Just one thing, if I  'path("${sample_name.log}") into test1_logs' it shows 'No such variable: log'.  
  > **username_1**: Erp there's a typo in there.. you'll need: `path("${sample_name}.log") into test1_logs` if your log's filename fits that format. Whether it does or not, you'll need to check. HTH.  
  > **username_0**: Let us [continue this discussion in chat](https://chat.stackexchange.com/rooms/121077/discussion-between-username_0-username_0-and-username_1).  
  > **username_0**: Thanks @username_1, I also tried it. If I use path("${sample_name}.log") , it shows error execution prosess; caused by missing output files. If I use path("${sample_name}".log) , it shows no such variable: log  
  > **username_1**: What's the name of your log file? I haven't run plink before, so I just used `"${sample_name}.log"` as an example. If the name of the log file is 'plink.log' then you'd use: `path("plink.log") into test1_logs` in your output declaration.  
  > **username_0**: Thanks @username_1, The final output.log is the log file. Sorry I failed to clarify. However, path("${sample_name}-t1.log") into test1_logs works as I expected! Thank a lot again.  
  
  ---
  
  