Troubleshooting#
This page collects the most common setup and runtime issues seen during development.
First Checks#
Before debugging a workflow failure, run:
thesis info
thesis show-config default
thesis run -w hcp -p 114823 -c default --dry-run
These commands usually reveal missing tools, wrong paths, or invalid merged config.
Missing External Tools#
antsApplyTransforms not found#
Install ANTs (or
conda install -c conda-forge ants) and make sure it is onPATH.Verify with
antsApplyTransforms --version.Atlas ROI transformation in the HCP workflow depends on this binary.
probtrackx2 not found#
Install FSL and verify that the FSL binaries are on
PATH.Confirm with
probtrackx2 --help.GPU-enabled runs may also require a working
probtrackx2_gpuorprobtrackx2_gpu11.0binary.
mri_synthseg not found#
mri_synthsegships with FreeSurfer; it is not bundled with the Python package. The standalone SynthSeg distribution also provides it.Use the
synthsegworkflow,tract_synthseg, orpreprocessonly after this binary is onPATH.
MRtrix3 binaries not found#
The
mrtrix3backend needs5ttgen,dwi2response,dwi2fod,mtnormalise,tckgen,tcksift2,tckmap, andmrconvertfrom MRtrix3 onPATH.thesis infoonly checks for FSL and ANTs, so it will not flag missing MRtrix3, FreeSurfer/SynthSeg, FSLeyes, or FireANTs — verify those manually.
Missing Input Files#
BedpostX samples are missing#
The HCP workflow expects merged thsamples, phsamples, and fsamples files.
Check:
hcp.bedpostx_dirthe subject input directory
whether the subject was preprocessed completely
Brain mask not found#
The default HCP path expects T1w/Diffusion/nodif_brain_mask.nii under the subject
input directory. Override hcp.mask_path if your layout differs.
ROI file or label CSV not found#
Confirm the path relative to the project root or use an absolute path.
When
label_nameis used,label_filemust exist and contain matching names.When using integer labels directly, prefer
label_values.
Config Problems#
Wrong patient-specific values are being used#
Remember the merge order:
config/default.yamlconfig/hardware.yamlconfig/protocols/{protocol}.yamlconfig/patients/{patient_id}.yamlCLI overrides
Use thesis show-config default to inspect the merged output.
GPU scheduling behaves unexpectedly#
Check:
hardware.gpu_enabledhardware.n_gpu_procshardware.n_gpusnipype.plugin_args
When GPU mode is enabled, the executor injects scheduler hints so concurrent GPU node launches stay bounded.
Nipype Runtime Issues#
Workflow starts but produces little output#
Use
-vfor verbose mode.Check the Nipype working directory from the run summary.
If progress bars are disabled automatically, confirm you are running in an interactive terminal.
A node fails and the CLI only shows a short message#
Re-run with
-v.Inspect the working directory or configured crash directory.
Reduce parallelism temporarily by lowering
nipype.plugin_args.n_procs.
Batch runs fail inconsistently#
Reduce
-j/--max-workers.Lower Nipype
n_procsor scheduler memory settings.Check whether multiple subjects are competing for one GPU.
MRtrix3 Gotchas#
tckgen produces 0 streamlines with brainstem seeds#
Symptom: a mrtrix3 or tract_synthseg (mrtrix3 backend) run completes the FOD stages but tckgen
reports zero streamlines, and tcksift2 then fails with a degenerate-input error.
Root cause: 5ttgen fsl returns a zero brainstem segmentation, so any seed dropped
into the brainstem lands in unsegmented tissue and is rejected silently.
Fix: switch to a FreeSurfer-based 5TT.
tractography:
fivett_algorithm: freesurfer # or "hsvs"
SIFT2 weights are not cross-subject comparable without mu#
Symptom: summing raw SIFT2 weights across subjects produces wildly different totals for similar tracts.
Root cause: tcksift2 weights are only meaningful in combination with the per-subject
mu scale factor (sum(weights) × mu / streamline_count defines Fibre Bundle Capacity).
The MRtrix3 workflow now captures mu automatically via tcksift2 -out_mu and writes
mu × Σ weights into waytotal. If you ever re-process the output by hand, make sure
to apply the same scaling, or use atlas.normalization_method: streamline_density
which assumes the workflow-provided waytotal semantics.
dwi2mask legacy over-erodes deep WM#
Symptom: a mrtrix3 run produces a handful of streamlines (e.g. 6 out of 2,000,000
attempted seeds) because the brain mask contains holes in deep WM (cerebral peduncle,
internal capsule).
Root cause: dwi2mask legacy erodes through low-FA regions.
Fix: reuse the FSL nodif_brain_mask.nii.gz (produced by preprocess) and dilate it
once. This is the default in the shipped mrtrix3.yaml:
tractography:
mask_source: fsl_nodif
mask_dilate_voxels: 1
If you must use dwi2mask, prefer b02template over legacy and verify the mask
visually (mrview dwi.mif -overlay.load mask.mif) before tracking.
Documentation and Developer Checks#
If you are changing the project during rapid development, verify docs and code health:
make check
make docs-strict
Workflow Preflight Errors#
Workflows declared with @requires(...) generate implicit existence checks
that run before the Nipype graph is built. When thesis run aborts with a
message like::
Required input 't1' not found at: data/...
the offending declaration is named in the error. Look in the workflow’s
factory function for the matching @requires entry. Common fixes:
Override the path via the appropriate config key (each
PatientFilelists itsconfig_pathschain).Add
fallback_dirs=[...]if the file legitimately lives somewhere other thaninput_dir.Pass
optional=Truewhen the workflow can run without that input.
Re-run with --dry-run to see all preflight errors at once without
launching Nipype.
Developer / Extension Errors#
These failures show up when authoring or composing workflows rather than running a shipped one.
Connecting to a non-existent inputnode/outputnode field#
Symptom: a meta-workflow build raises a Nipype connection error naming a field
that is not on the target’s inputnode / outputnode (e.g.
'roi_seeed' is not a valid input).
Root cause: meta-workflows wire contract-to-contract
(upstream.outputnode.<field> -> downstream.inputnode.<field>). The field name
must match a published contract field exactly.
Fix:
Look up the field tuples in
thesis.core.contracts(e.g.ROI_OUTPUT_FIELDS) and use the exact spelling.Confirm the sub-workflow actually publishes the field — find its
attach_inputnode(...)/attach_outputnode(...)call (seesrc/thesis/workflows/full_pipeline/_core.pyand the contracts section indocs/guides/nipype_integration.md).Never connect to a sub-workflow’s internal node name; rewire through the contract node instead.
Workflow registered twice / name collision#
Symptom: a warning (or, under strict mode, a ValueError) that a workflow name
is already registered.
Root cause: the module was imported twice, or two @workflow factories share a
name.
Fix:
Keep one
@workflowper file (the user-script loader enforces this — seedocs/guides/custom_workflows.md).Pick a unique
name; user scripts may not shadow a built-in workflow name.Set
THESIS_STRICT_REGISTRY=1to make duplicate registrations raise instead of warn, which surfaces accidental double-imports in tests immediately.
User-script config block rejected#
Symptom: config load fails with an unknown-key / validation error on your workflow’s YAML namespace.
Root cause: namespace blocks reject unknown keys, and the active schema does not declare the key you used.
Fix:
Check
config_namespace/config_schemaon the@workflowdecorator. With noconfig_schema, only keys named in@requiresconfig_pathsare accepted (auto-derived as optional strings) — see the auto-derived schema section indocs/guides/custom_workflows.md.For typed or extra keys, provide an explicit
config_schemaBaseConfigsubclass that declares them.
Still Stuck?#
Inspect
logs/for loguru output.Inspect
configuration/index.mdfor config semantics and per-section references.Inspect
workflows.mdfor workflow expectations.Run
thesis infoto confirm dependency detection.Run
thesis show-config <name>to inspect the merged config.
Documentation and Developer Checks#
If you are changing the project during rapid development, verify docs and code health:
make check
make docs-strict