Fix/clinvar prepare - #206
Conversation
A remote ClinVar was staged as a Nextflow foreign file, which every VEP task re-checks on its host with a HEAD request. On a multi-sample GRCh38 run NCBI answers that burst with HTTP 503, so SOMATIC_VEP failed with "Can't stage file ...clinvar_20260829.vcf.gz", and -resume could not recover because the failed check changed the staging cache key. The new VEPPLUGIN_CLINVAR step downloads the VCF and its index once per run, retrying 503s, and checks the VCF against --vep_clinvar_md5. The GRCh38 and CHM13 defaults carry the MD5 their hosts publish, so the pinned release cannot change silently; a user URL without an MD5 warns, and an MD5 with a local file is rejected. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Nextflow numbers eval() outputs across the whole pipeline and hashes that number, so one new eval() output shifts the cache key of every task that has one: a -resume of an existing run re-ran everything from METAEXTRACT on. A versions.yml path output leaves other tasks' hashes untouched. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ljwharbers
left a comment
There was a problem hiding this comment.
Thanks for this. The approach is sound: one download per run, the release's own basename kept, an MD5 pinned per genome, and versions.yml instead of eval() to protect the pipeline-wide eval counter. The new function tests are good. Two things need fixing before this merges (inline). The rest are nits.
What I checked
- The pinned MD5s match what the hosts publish:
dffae274…is in NCBI'sclinvar_20260829.vcf.gz.md5, and98bde679…is in Ensembl'sCHECKSUMS(MD5 format) for the CHM13 VCF. - The corrected sizes match
Content-Length: 193,427,450 bytes and 99,024,078 bytes. - The resolve → prepare → VEP wiring works:
--custom file=gets the basename, andch_extra_filesflattens[vcf, tbi]. The existing_tbi-required check still covers the fetch path, sotbi_urlis never null. - The 9 new function tests carry
tag "small", so PR CI runs them.
Should fix (inline)
vep_plugins/versions.ymlis published to the outdir, because the publishDir override has nosaveAs.s3://,gs://,az://andfile://ClinVar paths now go to wget and fail. Before this PR they were staged by Nextflow.
Nits
-resumeof an already completed run re-runs GERMLINE_VEP and SOMATIC_VEP once. ClinVar's input path moves fromwork/stage-<session>/…to theVEPPLUGIN_CLINVARwork dir, so both tasks get a new hash. That is expected and fine, but the PR stresses resume safety, so it deserves a line in the CHANGELOG.- The PR description says SV VEP also re-checked ClinVar. It doesn't:
SV_VEPgets[]and''for plugins (workflows/lrsomatic.nf:1009-1010). Only GERMLINE_VEP and SOMATIC_VEP were affected. - A remote
--vep_clinvarwith a local--vep_clinvar_tbipasses the local path to wget and fails with an unclear error. Eitherfile()-stage a local tbi or reject that combination invalidateVepPluginParams. Optional: the tbi is never checksum-checked. NCBI publishes no.tbi.md5, but Ensembl's CHECKSUMS lists the CHM13 tbi (50b634a69c36e2479cc2c8f71a8eafd6). docs/output.mdnever documentsvep_plugins/. That predates this PR, but the directory now holds ClinVar too.
CI: everything is green except docker | * | 4/7, which was still running after about 16 minutes (the other shards took 2–3). Worth checking before merge.
Happy to approve once 1 and 2 are addressed.
| // --vep_revel / --vep_eve (and their _tbi) at these files | ||
| withName : '.*:VEPPLUGIN_(REVEL|EVE)' { | ||
| // --vep_revel / --vep_eve / --vep_clinvar (and their _tbi) at these files | ||
| withName : '.*:VEPPLUGIN_(REVEL|EVE|CLINVAR)' { |
There was a problem hiding this comment.
This block replaces the default publishDir, and the default is where the saveAs that drops versions.yml lives. REVEL and EVE report their versions through topics, so this never mattered for them. VEPPLUGIN_CLINVAR emits a versions.yml, so every run now publishes <outdir>/vep_plugins/versions.yml.
| withName : '.*:VEPPLUGIN_(REVEL|EVE|CLINVAR)' { | |
| withName : '.*:VEPPLUGIN_(REVEL|EVE|CLINVAR)' { | |
| publishDir = [ | |
| mode: params.publish_dir_mode, | |
| path: { "${params.outdir}/vep_plugins" }, | |
| saveAs: { filename -> filename.equals('versions.yml') ? null : filename } | |
| ] | |
| } |
| def value = vepPluginResource(data_param) | ||
| return value && | ||
| data_param == 'vep_clinvar' && | ||
| value.toString().contains('://') |
There was a problem hiding this comment.
contains('://') also catches s3://, gs://, az:// and file://. Before this PR, file() staged those through Nextflow's filesystem providers. Now they reach wget, which fails with Unsupported scheme. A cloud run pointing --vep_clinvar at a bucket copy would break. REVEL and EVE use the same test, but this is the only one whose behaviour changes.
Suggest restricting it to what wget can fetch:
value.toString() ==~ /(?i)^(https?|ftp):\/\/.*/Plus a function test where an s3:// ClinVar gives false.
|
|
||
| tag "modules" | ||
| tag "modules_local" | ||
| tag "vepplugin_clinvar" |
There was a problem hiding this comment.
Nit: PR CI runs only tag "small" tests (.github/workflows/nf-test.yml:53,102). The nf-test-changes job lists this test, but no shard runs it. It is a stub test, so adding tag "small" costs nothing.
| wget \\ | ||
| --no-verbose \\ | ||
| --tries=5 \\ | ||
| --waitretry=30 \\ |
There was a problem hiding this comment.
Nit: --waitretry sets the maximum of a linear backoff (1 s, 2 s, … up to 30 s), so with --tries=5 the total wait is about 1+2+3+4 = 10 s. That is probably enough now that there's only one request, but the comment reads as if it covers more. If NCBI stays unavailable for longer, --tries=10 (about 45 s in total) would be a cheap margin.
… CHM13 index - Don't publish VEPPLUGIN_CLINVAR's versions.yml to vep_plugins/: the publishDir override lacked the default saveAs. - Fetch ClinVar only for http(s)/ftp URLs; s3://, gs://, az:// and file:// are staged by Nextflow again, as before this PR. - Reject a downloaded ClinVar paired with a local --vep_clinvar_tbi, which wget could not fetch. - Add --vep_clinvar_tbi_md5, pinned by default to the MD5 Ensembl publishes for the CHM13 index; NCBI publishes none for GRCh38. - wget --tries=10 (about 45 s of linear backoff), tag the module test "small" so PR CI runs it, and document vep_plugins/ in output.md. - Correct the wording: only GERMLINE_VEP and SOMATIC_VEP staged ClinVar, never SV_VEP; note the one-off VEP re-run on resume. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Problem
Multi-sample GRCh38 runs fail in
SOMATIC_VEPwith:ClinVar was staged as a Nextflow foreign file. Every VEP task that uses it (germline, somatic and SV, per sample) re-checks it on NCBI with a HEAD request, and NCBI answers the resulting burst with HTTP 503. Twenty parallel HEAD requests got about half 503s. When a check fails, the staging cache key changes, so Nextflow downloads the file again, and all 3 retries fail within a second.
-resumecannot recover. A 2-sample run gets through; an 8-sample run fails every time.Fix
VEPPLUGIN_CLINVAR, called fromPREPARE_VEP_PLUGINS:.tbionce per run, retrying 429/5xx responses;--custom file=argument is unchanged;<outdir>/vep_plugins/.--vep_clinvar_md5:.md5, EnsemblCHECKSUMS), so the pinned release cannot change silently;--vep_clinvardrops the default MD5, the same rule as the default index;--vep_clinvar_md5with a local file is an error.--vep_clinvaris still staged as given.Two implementation notes:
versions.yml, not aneval()topic. Nextflow numberseval()outputs across the whole pipeline and hashes that number, so one neweval()output changed the cache key of every task that has one, and-resumeof an existing run re-ran everything fromMETAEXTRACTon. Confirmed with a two-process reproduction.conf/modules.configpasses--no-check-certificate, as the existingWGETconfig does. The MD5 check covers integrity.Testing
nf-test(singularity): 34 function tests inutils_nfcore_lrsomatic_pipeline/tests/main.function.nf.test, 9 of them new, plus a new stub test forVEPPLUGIN_CLINVAR. All pass.VEPPLUGIN_CLINVARran once withclinvar_20260829.vcf.gz: OK;ClinVar_CLNSIG,ClinVar_CLNREVSTATandClinVar_CLNDN.nextflow lintreports no new errors or warnings, and pre-commit passes.skip_vep_plugins = true, so their snapshots are unchanged.Also corrects the ClinVar download sizes in
docs/usage.md(193 MB for GRCh38, 99 MB for CHM13).🤖 Generated with Claude Code
PR checklist
nf-core pipelines lint).nextflow run . -profile test,docker --outdir <OUTDIR>).nextflow run . -profile debug,test,docker --outdir <OUTDIR>).docs/usage.mdis updated.docs/output.mdis updated.CHANGELOG.mdis updated.README.mdis updated (including new tool citations and authors/contributors).