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.
Bug report
Expected behavior and actual behavior
A channel factory provided by a plugin (an
@Factorymethod on aPluginExtensionPoint, included withinclude { fromQuery } from 'plugin/nf-sqldb') should be callable aschannel.<name>(...)whether or not the script enables static typing.With
nextflow.enable.types = true, no plugin channel factory can be reached.channel.fromQuery(...)fails withMissing process or function fromQuery(...), even though theincludesucceeds. 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:untyped.nfis the same file without the first line.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
fromStorefactory works in untyped scripts. The typed-script behavior is the same for any plugin factory.Program output
From
.nextflow.log:Cause
ScriptCompilerbindschannelto 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):nextflow.Channelforwards unknown factory names to plugins (modules/nextflow/src/main/groovy/nextflow/Channel.groovy, lines 80-81):nextflow.dataflow.ChannelNamespacedefines only the built-in factories (empty,fromLineage,fromList,fromPath,interval,of,topic,value,watchPath) and has no equivalent, so a plugin factory registered inPluginExtensionProvider.factoryExtensionsis never consulted. This is still the case onmasterat bbf6ff0.Using
Channel.fromQuery(...)in a typed script doesn't help, because thereChannelresolves to the typenextflow.script.types.Channel.Suggested fix
Give
ChannelNamespacethe same fallback, converting the plugin's v1 channel to the v2 type the rest of the namespace returns. Something like:The static type checker may also need to accept included plugin factories on the
channelnamespace (nextflow.script.namespaces.ChannelNamespacein 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:
Environment
nextflow rundirectly)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.