Spike — synthetic scenario pipelines on two Nextflow versions and Snakemake (2026-10-26)¶
Question. Can one pair of twin pipelines reproduce, on both engines, every gate and failure scenario that Spectio must handle? Can the stop and resume mechanisms Spectio would generate be verified automatically?
Answer. Yes. All 11 PR scenarios pass on Nextflow 26.10.3, Nextflow 25.10.9 and Snakemake 9.27.1, with the local executor.
Engine faults found:
- Snakemake: one known engine fault, seen in 4 of 18 executions of one scenario. It is handled by a targeted repeat and reported as
PASS*. - Nextflow: one version difference that changes how timeouts must be classified.
Setup¶
- Machine. Claude Code cloud session: 2 CPUs, Linux 6.18, Java 21, Docker started by hand (cgroup v1).
-
Engines:
- Nextflow 26.10.3 and 25.10.9 (release binaries from GitHub,
NXF_HOMEin the scratchpad); - Snakemake 9.27.1 (
uv tool install snakemake==9.27.1).
- Nextflow 26.10.3 and 25.10.9 (release binaries from GitHub,
-
Code:
tests/pipelines/synthetic/:nextflow/main.nf,snakemake/workflow/Snakefile,bin/synth.py;scenarios.yaml, run byrun_scenarios.py.
-
Commands:
python3 run_scenarios.py --engine nextflow --nextflow ~/bin/nextflow-26.10.3 --workdir /tmp/sc/nf26 python3 run_scenarios.py --engine nextflow --nextflow ~/bin/nextflow-25.10.9 --workdir /tmp/sc/nf25 python3 run_scenarios.py --engine snakemake --workdir /tmp/sc/smk
Results (final run, after the fixes below)¶
| Scenario | NF 26.10.3 | NF 25.10.9 | Snakemake 9.27.1 |
|---|---|---|---|
| happy (65 tasks) | PASS 16.0 s | PASS 15.9 s | PASS 4.1 s |
| gate_qc_then_resume (≥ 25 cached) | PASS | PASS | PASS |
| gate_align_then_resume (≥ 49 cached) | PASS | PASS | PASS |
| exclude_sample_and_resume | PASS | PASS | PASS |
| flaky_retry | PASS | PASS | PASS |
| oom_once_retry | PASS | PASS | PASS* (finding 1) |
| oom_fatal | PASS | PASS | PASS |
| timeout_fatal | PASS 36.8 s | PASS 35.9 s | PASS 25.7 s |
| tool_error_then_fixed_resume | PASS | PASS | PASS |
| dynamic_fanout (45 ALIGN) | PASS | PASS | PASS |
| fanout_medium (180 ALIGN) | PASS 40.7 s | PASS 45.9 s | PASS 12.8 s |
Where the numbers come from.
- Nextflow: the scratchpad files
final/nf-26.10.3.txtandfinal/nf-25.10.9.txt(one full run each). - Snakemake:
final2/smk.txt, a full run after the known-fault rule was added. Itsoom_once_retryhit the fault, was repeated once, and passed.- An earlier full run, made before the rule existed (
final/smk.txt), failed on that scenario: 10 / 11. - A correction: the first version of this note had the two Nextflow columns swapped.
- An earlier full run, made before the rule existed (
The counts matrix (quant/counts_matrix.tsv) is byte-identical between the two engines (diff).
Findings¶
-
Snakemake 9.27.1 can lose a retried job when a checkpoint updates the DAG at the same moment.
- What happens. In
oom_once_retry,qc_statsfor S05 fails (137), and Snakemake logs "Trying to restart job 10".checkpoint splitthen finishes, and Snakemake logs "Updating checkpoint dependencies". The restart is never executed. The run ends with "BUG: Out of jobs ready to be started, but not all files built yet. Please check https://github.com/snakemake/snakemake/issues/823". - How often. 4 of the 18 executions of
oom_once_retryobserved in this session (two full suites, a loop of 8, a loop of 6, and the 2 repeats, both of which passed). - Recovery. A plain rerun in the same directory completes the run (exit 0, 3 of 3 steps).
- Consequences:
- For the tests:
scenarios.yamlhas anengine_faultslist. A failed scenario whose logs contain that message is repeated once, from scratch, and reported asPASS*with the fault ID. Any other failure fails the build. - For Spectio: a new failure class, engine scheduling fault (
schedulers-and-monitoring.md§3.5). The suggested action is "rerun"; no resources change.
- For the tests:
- What happens. In
-
A local time limit has no exit code on Nextflow 25.10.9.
- 25.10.9: the task's trace status is
FAILEDwith exit-, the error message is "Process exceeded running time limit (4s)", andtask.exitStatusisInteger.MAX_VALUE. A retry rule that matches only[137, 140, 143]does not retry, sotimeout_fatalsaw 1 failed attempt instead of 3. - 26.10.3: the same kill gives exit 143.
- Fix in the test pipeline: retry on
Integer.MAX_VALUEas well (nextflow.config). - For Spectio: classify timeouts from the trace status and error text, not from the exit code alone.
- 25.10.9: the task's trace status is
-
Nextflow's quiet console output has no "cached" summary line on 25.10.9. The runner now counts
CACHEDrows inexecution_trace.txt, which works on both versions. Spectio's ingest also takes cached counts from task records, never from console text. - Nextflow parameters from the command line are strings.
--chunks 0is the string"0", which is true in Groovy, so the dynamic fan-out never triggered. The fix is(params.chunks as int) > 0. Spectio's launch forms must type parameters from the pipeline schema. The parameters file is JSON, so its types survive. - Snakemake does not format
{resources.attempt}insideparams. The attempt number reached the failure hook as the literal text, soflakyandoom_oncealways failed. The fix is to exportSPECTIO_ATTEMPT={resources.attempt}at the start of every shell command. - Snakemake wildcards need constraints next to directory outputs.
directory("chunks/{sample}")also matched chunk files untilwildcard_constraintsrestrictedsampleto[A-Za-z0-9]+. -
The gate mechanisms hold on both engines:
- a generated Nextflow config setting
ext.when = falseon later processes, then-resume, gives 25 cached tasks afterqcand 49 afteralign; - Snakemake
--until, then a plain rerun, recomputes nothing upstream.
This is the mechanism described in
checking-scenarios.md. - a generated Nextflow config setting
Not covered here¶
- SLURM (sind) and Kubernetes (kind): this session's cgroup v1 Docker cannot run sind. These legs are steps T3 and T4.
- Nightly
fanout_stress(about 12 000 ALIGN tasks): not run in this session. - The rest of the real corpus: only nf-core/demo was run here (below). The other nf-core and catalog entries are run by
pipelines-real.yml.
Addendum: nf-core/demo 1.2.0 with Docker in this session¶
Result. python3 tests/pipelines/real/run_corpus.py --engine nextflow --name demo --limits auto --nextflow nextflow-26.10.3 → PASS in 104 s:
- 8 tasks completed, 0 failed (FASTQC, SEQTK_TRIM, COWPY, MULTIQC);
- outputs:
cowpy,fastqc,fq,multiqc,pipeline_info; - containers were pulled from quay.io and
community.wave.seqera.iothrough the session proxy.
Two fixes to the corpus runner came out of it:
-
Clone with git instead of
nextflow run nf-core/demo -r 1.2.0.- Nextflow reads the project manifest through the GitHub API. Through the session proxy this gave "Forbidden -- Provide your GitHub user name and password". Unauthenticated API calls are also limited per hour on CI runners [to be validated: current limit].
- The runner now runs
git clone --depth 1 --branch <version>andnextflow run <dir>. - Spectio's launcher should do the same, or pass a token, for pinned releases.
-
Resource limits must stay below the memory that is free, not the memory that is installed.
- With
process.resourceLimitsat 7 GB on an 8 GB machine, COWPY asked for 6 GB and the local executor refused it: "Task requirement exceeds available memory -- req: 6 GB; avail: 5.8 GB". The error isProcessUnrecoverableException, with no exit code. --limits autonow uses 80 % ofMemAvailable, which was 5 GB here.- For Spectio: the pre-flight check should compare process requests with the target's real headroom (
schedulers-and-monitoring.md§3.5). This error should be classed as a resource request that cannot be met, not as a tool error.
- With