Skip to content

Plugin channel factories are unreachable via channel.* when nextflow.enable.types = true #7694

Description

@robsyme

Bug report

Expected behavior and actual behavior

A channel factory provided by a plugin (an @Factory method on a PluginExtensionPoint, included with include { fromQuery } from 'plugin/nf-sqldb') should be callable as channel.<name>(...) whether or not the script enables static typing.

With nextflow.enable.types = true, no plugin channel factory can be reached. channel.fromQuery(...) fails with Missing process or function fromQuery(...), even though the include succeeds. The same script without the flag reaches the plugin.

Steps to reproduce the problem

nextflow.config:

plugins { id 'nf-sqldb' }
sql.db.demo.url = 'jdbc:h2:mem:demo'

typed.nf:

nextflow.enable.types = true

include { fromQuery } from 'plugin/nf-sqldb'

workflow {
    channel.fromQuery('SELECT 1 AS x', db: 'demo').view()
}

untyped.nf is the same file without the first line.

nextflow run untyped.nf
nextflow run typed.nf

The untyped run gets into nf-sqldb's own code. It then fails with 'boolean nextflow.NF.isDsl2()', which is a separate incompatibility between nf-sqldb 0.7.1 and 26.04, but it shows the factory was resolved. The typed run never reaches the plugin.

I hit this first with a plugin of my own, whose fromStore factory works in untyped scripts. The typed-script behavior is the same for any plugin factory.

Program output

$ nextflow run typed.nf
[ERROR] Missing process or function fromQuery([[db:demo], SELECT 1 AS x])

 -- Check script 'typed.nf' at line: 6 or see '.nextflow.log' file for more details

From .nextflow.log:

Caused by: groovy.lang.MissingMethodException: No signature of method: static nextflow.dataflow.ChannelNamespace.fromQuery() is applicable for argument types: (LinkedHashMap, String) values: [[db:demo], SELECT 1 AS x]
	at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1652)

Cause

ScriptCompiler binds channel to a different class when typing is enabled (modules/nextflow/src/main/groovy/nextflow/script/parser/v2/ScriptCompiler.java, lines 311-313 at v26.04.6):

var channelNamespace = sn.isTypingEnabled()
    ? ClassHelper.makeWithoutCaching("nextflow.dataflow.ChannelNamespace")
    : ClassHelper.makeWithoutCaching("nextflow.Channel");

nextflow.Channel forwards unknown factory names to plugins (modules/nextflow/src/main/groovy/nextflow/Channel.groovy, lines 80-81):

static def $static_methodMissing(String name, Object args) {
    PluginExtensionProvider.INSTANCE().invokeFactoryExtensionMethod(name, InvokerHelper.asArray(args))
}

nextflow.dataflow.ChannelNamespace defines only the built-in factories (empty, fromLineage, fromList, fromPath, interval, of, topic, value, watchPath) and has no equivalent, so a plugin factory registered in PluginExtensionProvider.factoryExtensions is never consulted. This is still the case on master at bbf6ff0.

Using Channel.fromQuery(...) in a typed script doesn't help, because there Channel resolves to the type nextflow.script.types.Channel.

Suggested fix

Give ChannelNamespace the same fallback, converting the plugin's v1 channel to the v2 type the rest of the namespace returns. Something like:

static def $static_methodMissing(String name, Object args) {
    final result = PluginExtensionProvider.INSTANCE().invokeFactoryExtensionMethod(name, InvokerHelper.asArray(args))
    return DataflowTypeHelper.normalize(result, true)   // DataflowWriteChannel -> ChannelImpl
}

The static type checker may also need to accept included plugin factories on the channel namespace (nextflow.script.namespaces.ChannelNamespace in nf-lang), so that the language server doesn't flag them.

Workaround

Calling the legacy class by its full name works in a typed script:

nextflow.Channel.fromQuery(...)

Environment

  • Nextflow version: 26.04.6
  • Java version: OpenJDK 21.0.11
  • Operating system: macOS 27.0
  • Bash version: not relevant (reproduced with nextflow run directly)

Additional context

Static typing is a preview feature, so this may already be on the roadmap. Plugin factories are the main way plugins supply input channels, though (nf-sqldb, and plugins such as mine that read from a lineage store), so until this is fixed a typed pipeline can't use any of them.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions