Step 1: Identify Which Subjects Failed¶
Run Post-Run Verification first. Use check-outputs to see which subjects are missing expected output files, and the job database for exit codes and error messages. Once you know which subjects and tasks need attention, come back here to diagnose why.
Step 2: Read the SLURM Logs¶
SLURM output and error files are in {work_dir}/log/{task_name}/, where {work_dir} is the run --work with the project name appended (e.g. /data/work/my_study):
# Array jobs
{work_dir}/log/{task_name}/{task_name}_{job_id}-{array_task_id}.out
{work_dir}/log/{task_name}/{task_name}_{job_id}-{array_task_id}.err
# Non-array jobs
{work_dir}/log/{task_name}/{task_name}_{job_id}.out
{work_dir}/log/{task_name}/{task_name}_{job_id}.errThe detailed per-subject execution log (stdout + stderr combined) is written by the wrapper:
# Array jobs
{work_dir}/log/{task_name}/sub-{subject}/{task_name}_{job_id}_{array_task_id}_{timestamp}.log
# Non-array jobs
{work_dir}/log/{task_name}/{task_name}_{job_id}_{timestamp}.logStep 3: Inspect the Wrapper Script¶
The generated wrapper script shows exactly what ran on the compute node:
cat /data/work/my_study/log/wrapper/afni_cards_preprocessing_*.shVerify:
Module load commands look correct
Environment variables (
$TEMPLATE_DIR,$CONTAINER_DIR, etc.) are setScript path exists
Step 4: Test the Module Environment¶
SSH to a compute node (or use srun) and manually load the modules:
srun --pty bash
ml AFNI/24.3.06-foss-2023a
afni_proc.py --help # should print help if loaded correctlyStep 5: Check Script Line Endings¶
Windows line endings cause $'\r': command not found errors:
# Run inside the scripts_dir set in your project config
file afni_cards_preprocessing.sh
# Should say "POSIX shell script" or "Bourne-Again shell script", NOT "CRLF"
# Fix if needed:
dos2unix *.shDatabase Shows Incomplete Records?¶
If the database is missing jobs (e.g., after a cluster crash), merge the raw JSONL logs manually. Pass the run --work directory, without the project name:
neuromaestro merge-logs /data/workJSONL event logs in the json/ directory next to the database (/data/work/database/json/ by default) accumulate independently of the SQLite database. Merging re-processes any unarchived files and fills in gaps.
If the JSONL files were already archived by a previous merge and the database is still incomplete (e.g., after restoring from backup), use force-rebuild to create a fresh database from all logs including archived ones:
neuromaestro force-rebuild /data/work
# → writes pipeline_jobs_rebuild_{timestamp}.db next to the originalQuick Diagnosis Checklist¶
Is the config file named
{project}_config.yamland in the right directory?Does
module availshow the modules in your config?Are all paths in
envir_dirabsolute and correct on the HPC?Does the container
.siffile exist incontainer_dir?Does the
license.txtexist infreesurfer_dir?Are shell scripts using Unix line endings?
Does the Python venv on the compute nodes contain
typer?
Error Reference¶
Setup & Configuration¶
“No subjects found”
Check that
prefixin your project config (prefix: "sub-") matches your directory namingVerify
--inputpoints to the correct directoryRun
neuromaestro detect-subjects /data/BIDSto preview what the pipeline sees
“Config not found: .../{project}_config.yaml”
The config file must be named exactly
{project}_config.yamlIt must be in
<config-dir>/project_config/Check:
ls <config-dir>/project_config/
“Task not found” / task name mismatch
Task names are case-sensitive —
cards_preprocess≠Cards_PreprocessThe name must match exactly between
config.yamland your project configtaskssectionRun
neuromaestro list-tasksto see all registered task names
GUI won’t start
Check if port 8050 is already in use:
lsof -i :8050Try a different port:
neuromaestro-gui --port 8051Verify the package is installed:
pip show neuromaestro
SLURM & Job Submission¶
module: command not found in job logs
The module system is not initialized in the batch environment
Add to the top of
global_pythonin your project config:global_python: - source /etc/profile.d/modules.sh - ml Python/3.11.3-GCCcore-12.3.0 - . /home/$USER/venv/bin/activate
SLURM Job ID: N/A in the per-subject log
The wrapper ran without a SLURM job ID, so it was not started as a SLURM job (for example it was run directly with
bash)Check:
which sbatch(must be available)Check account:
sacctmgr show user $USER
Jobs are queued but never start
Check resource limits:
sacctmgr show assoc user=$USERReduce concurrent array jobs: lower
array_limiton the task’s resource profile inhpc_config.yaml
Container Mounting (Apptainer / Singularity)¶
FATAL: container creation failed: ... squashfuse_ll failed to mount ... in 10s
Apptainer mounts a .sif image with squashfuse (a userspace FUSE mount) and gives up if the mount is not ready within a hard 10 second limit. The image lives on the shared network filesystem (container_dir, e.g. /work). When many jobs mount the same large image at the same time (a job array releasing a batch at once), they all read the image over the network and contend for storage bandwidth, so individual mounts exceed 10s and fail.
This is probabilistic, not deterministic. It is far more likely with:
Large images (fMRIPrep, QSIPrep, QSIRecon, MRIQC are 10 to 20 GB)
High concurrency (many array tasks starting in the same window)
Peak cluster hours (Monday morning, weekday daytime) and shared (non-dedicated) nodes
The bundled ds027 example scripts avoid this by staging the image to node-local disk before running. The template scripts that neuromaestro init copies do not include this block, so add it to your own container scripts if you see the timeout. The block works as follows:
The image is copied once to
/tmp/${USER}_sif/on the compute node, and the container runs from that local copy. A local squashfuse mount completes in well under a second, so the 10s timeout never triggers.A per-node
flockguarantees only one job on a node copies the image; other jobs wait and then reuse the same copy, so a burst of same-node jobs does not each copy in parallel.If staging fails (see disk-full below), the script prints a warning and falls back to the network image, so the job still runs.
APPTAINER_TMPDIR/SINGULARITY_TMPDIRare also pointed at node-local disk for session scratch.
This is the block near the top of each ds027 container script (before singularity run). Copy it into any container script, then run singularity run ... ${local_container} ... instead of ${CONTAINER_DIR}/${CONTAINER}:
# Point Apptainer session/cache to node-local disk to avoid squashfuse mount timeout
apptainer_tmp="${SLURM_TMPDIR:-${TMPDIR:-/tmp}}/apptainer_${SLURM_JOB_ID:-$$}"
mkdir -p "${apptainer_tmp}"
export APPTAINER_TMPDIR="${apptainer_tmp}"
export APPTAINER_CACHEDIR="${apptainer_tmp}"
export SINGULARITY_TMPDIR="${apptainer_tmp}"
export SINGULARITY_CACHEDIR="${apptainer_tmp}"
# Stage container image to node-local disk to avoid squashfuse mount timeout.
# Per-node lock: only one job copies, others wait then reuse. Fall back to the
# network image if staging fails (e.g. local disk full).
src_container="${CONTAINER_DIR}/${CONTAINER}"
node_cache="/tmp/${USER}_sif"
staged="${node_cache}/${CONTAINER}"
local_container="${src_container}"
mkdir -p "${node_cache}" 2>/dev/null
(
flock 9
if [ ! -s "${staged}" ] || [ "$(stat -c%s "${staged}" 2>/dev/null)" != "$(stat -c%s "${src_container}")" ]; then
tmp_copy="${staged}.tmp.$$"
cp "${src_container}" "${tmp_copy}" 2>/dev/null && mv -f "${tmp_copy}" "${staged}" || rm -f "${tmp_copy}"
fi
) 9>"${node_cache}/${CONTAINER}.lock"
if [ -s "${staged}" ] && [ "$(stat -c%s "${staged}" 2>/dev/null)" = "$(stat -c%s "${src_container}")" ]; then
local_container="${staged}"
else
echo "WARNING: staging to ${node_cache} failed (disk full?), using network image"
fiIf mount timeouts still appear (staging fell back to the network image), also:
Lower concurrency via
array_limiton the task’s resource profile inhpc_config.yamlSubmit off-peak, or use dedicated nodes when available
cp: ... No space left on device when staging the image
Node-local /tmp filled up. On shared nodes /tmp is shared with other users’ jobs, so it can be nearly full before your copy starts. Scripts with the staging block handle this gracefully (fall back to the network image), so the job does not hard-fail, but that job loses the staging benefit.
Inspect a compute node:
srun --pty bash -c 'df -h -T /tmp; du -sh /tmp/${USER}_sif'Clear your own leftovers on a node:
srun -w <node> bash -c 'rm -rf /tmp/${USER}_sif'Most clusters reap
/tmpautomatically (epilog or tmpwatch); only your own files (/tmp/${USER}_sif,/tmp/apptainer_*) are yours to remove
Python Environment¶
ModuleNotFoundError: No module named 'typer'
The Python environment on the compute node is missing required packages
Ensure your venv/conda env includes
typer, which the wrapper’s job logger imports. Everything else it uses is in the Python standard libraryTest on a compute node:
srun --pty bash -c "source /path/to/venv/bin/activate && python -c 'import typer'"
Resume & Output Checks¶
--resume does not skip any subjects
Check that
{project}_checks.yamlexists in<config-dir>/results_check/Tasks with no entry in the checks file are always submitted in full (warning is printed)
--resumedoes not filter subjects during--dry-run, so a dry-run always lists every subject--resumeresolves{work_dir}in the checks file to--outputwith the project name appended. Runcheck-outputswith that path as--workto see what--resumesees
check-outputs reports unexpected failures
Open the CSV at
{--work}/check_results_{timestamp}.csv. Thepatterncolumn shows the check’s pattern as written in the checks file (relative tooutput_path, placeholders not filled in), andactualshows how many files matchedVerify
output_pathresolves correctly for your subjects by checking the path manually on the HPCCheck
expected_countandtolerancematch your actual data