Errors and Crashes

Probably the most important chapter in this section is about how to handle error and crashes. Because at the beginning you will run into a few.

For example:

  1. You specified file names or paths that don't exist.
  2. You try to give an interface a string as input, where a float value is expected or you try to specify a parameter that doesn't exist. Be sure to use the right input type and input name.
  3. You wanted to give a list of inputs [func1.nii, func2.nii, func3.nii] to a node that only expects one input file . MapNode is your solution.
  4. You wanted to run SPM's motion correction on compressed NIfTI files, i.e. *.nii.gz? SPM cannot handle that. Nipype's Gunzip interface can help.
  5. You haven't set up all necessary environment variables. Nipype for example doesn't find your MATLAB or SPM version.
  6. You forget to specify a mandatory input field.
  7. You try to connect a node to an input field that another node is already connected to.

Important note about crashfiles. Crashfiles are only created when you run a workflow, not during building a workflow. If you have a typo in a folder path, because they didn't happen during runtime, but still during workflow building.

Example Crash 1: File doesn't exist

When creating a new workflow, very often the initial errors are IOError, meaning Nipype cannot find the right files. For example, let's try to run a workflow on sub-06, that in our dataset doesn't exist.

Creating the crash


In [ ]:
from nipype import SelectFiles, Node, Workflow
from os.path import abspath as opap
from nipype.interfaces.fsl import MCFLIRT, IsotropicSmooth

# Create SelectFiles node
templates={'func': '{subject_id}/func/{subject_id}_task-flanker_run-1_bold.nii.gz'}
sf = Node(SelectFiles(templates),
          name='selectfiles')
sf.inputs.base_directory = opap('/data/ds102')
sf.inputs.subject_id = 'sub-06'

# Create Motion Correction Node
mcflirt = Node(MCFLIRT(mean_vol=True,
                       save_plots=True),
               name='mcflirt')

# Create Smoothing node
smooth = Node(IsotropicSmooth(fwhm=4),
              name='smooth')

# Create a preprocessing workflow
wf = Workflow(name="preprocWF")
wf.base_dir = 'working_dir'

# Connect the three nodes to each other
wf.connect([(sf, mcflirt, [("func", "in_file")]),
            (mcflirt, smooth, [("out_file", "in_file")])])

# Let's the workflow
wf.run()


170301-22:04:38,683 workflow INFO:
	 ['check', 'execution', 'logging']
170301-22:04:38,688 workflow INFO:
	 Running serially.
170301-22:04:38,689 workflow INFO:
	 Executing node selectfiles in dir: /home/jovyan/work/notebooks/working_dir/preprocWF/selectfiles
170301-22:04:38,700 workflow ERROR:
	 ['Node selectfiles failed to run on host 74a339115575.']
170301-22:04:38,704 workflow INFO:
	 Saving crash info to /home/jovyan/work/notebooks/crash-20170301-220438-jovyan-selectfiles-63aef326-1156-4573-8c1c-d89cc999b0fe.pklz
170301-22:04:38,705 workflow INFO:
	 Traceback (most recent call last):
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/plugins/linear.py", line 39, in run
    node.run(updatehash=updatehash)
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/nodes.py", line 394, in run
    self._run_interface()
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/nodes.py", line 504, in _run_interface
    self._result = self._run_command(execute)
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/nodes.py", line 630, in _run_command
    result = self._interface.run()
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.py", line 1044, in run
    outputs = self.aggregate_outputs(runtime)
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.py", line 1115, in aggregate_outputs
    predicted_outputs = self._list_outputs()
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/io.py", line 1319, in _list_outputs
    raise IOError(msg)
IOError: No files were found matching func template: /data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz
Interface SelectFiles failed to run. 

170301-22:04:38,718 workflow INFO:
	 ***********************************
170301-22:04:38,720 workflow ERROR:
	 could not run node: preprocWF.selectfiles
170301-22:04:38,721 workflow INFO:
	 crashfile: /home/jovyan/work/notebooks/crash-20170301-220438-jovyan-selectfiles-63aef326-1156-4573-8c1c-d89cc999b0fe.pklz
170301-22:04:38,722 workflow INFO:
	 ***********************************
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
<ipython-input-1-0f743cd10242> in <module>()
     28 
     29 # Let's the workflow
---> 30 wf.run()

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/workflows.pyc in run(self, plugin, plugin_args, updatehash)
    595         if str2bool(self.config['execution']['create_report']):
    596             self._write_report_info(self.base_dir, self.name, execgraph)
--> 597         runner.run(execgraph, updatehash=updatehash, config=self.config)
    598         datestr = datetime.utcnow().strftime('%Y%m%dT%H%M%S')
    599         if str2bool(self.config['execution']['write_provenance']):

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/plugins/linear.pyc in run(self, graph, config, updatehash)
     55                 if self._status_callback:
     56                     self._status_callback(node, 'exception')
---> 57         report_nodes_not_run(notrun)

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/plugins/base.pyc in report_nodes_not_run(notrun)
     93                 logger.debug(subnode._id)
     94         logger.info("***********************************")
---> 95         raise RuntimeError(('Workflow did not execute cleanly. '
     96                             'Check log for details'))
     97 

RuntimeError: Workflow did not execute cleanly. Check log for details

Investigating the crash

Hidden, in the log file you can find the relevant information:

IOError: No files were found matching func template: /data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz
Interface SelectFiles failed to run. 

170301-13:04:17,458 workflow INFO:
     ***********************************
170301-13:04:17,460 workflow ERROR:
     could not run node: preprocWF.selectfiles
170301-13:04:17,461 workflow INFO:
     crashfile: /home/jovyan/work/notebooks/crash-20170301-130417-mnotter-selectfiles-45206d1b-73d9-4e03-a91e-437335577b8d.pklz
170301-13:04:17,462 workflow INFO:

This part tells you that it's an IOError and that it looked for the file /data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz.

After the line ***********************************, you can additional see, that it's the node preprocWF.selectfiles that crasehd and that you can find a crashfile to this crash under /home/jovyan/work/notebooks/.

Reading the crashfile

To get the full picture of the error, we can read the content of the crashfile with the bash command nipype_display_crash. We will get the same information as above, but additionally, we can also see directly the input values of the Node that crashed.


In [ ]:
!nipype_display_crash /home/jovyan/work/notebooks/crash-*selectfiles-*.pklz



File: /home/jovyan/work/notebooks/crash-20170301-220438-jovyan-selectfiles-63aef326-1156-4573-8c1c-d89cc999b0fe.pklz
Node: preprocWF.selectfiles
Working directory: /home/jovyan/work/notebooks/working_dir/preprocWF/selectfiles


Node inputs:

base_directory = /data/ds102
force_lists = False
ignore_exception = False
raise_on_empty = True
sort_filelist = True
subject_id = sub-06



Traceback: 
Traceback (most recent call last):
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/plugins/linear.py", line 39, in run
    node.run(updatehash=updatehash)
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/nodes.py", line 394, in run
    self._run_interface()
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/nodes.py", line 504, in _run_interface
    self._result = self._run_command(execute)
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/nodes.py", line 630, in _run_command
    result = self._interface.run()
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.py", line 1044, in run
    outputs = self.aggregate_outputs(runtime)
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.py", line 1115, in aggregate_outputs
    predicted_outputs = self._list_outputs()
  File "/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/io.py", line 1319, in _list_outputs
    raise IOError(msg)
IOError: No files were found matching func template: /data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz
Interface SelectFiles failed to run. 



Example Crash 2: Wrong Input Type or Typo in the parameter

Very simple, if an interface expects a float as input, but you give it a string, it will crash:


In [ ]:
from nipype.interfaces.fsl import IsotropicSmooth
smooth = IsotropicSmooth(fwhm='4')


---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-3-38d0489c2381> in <module>()
      1 from nipype.interfaces.fsl import IsotropicSmooth
----> 2 smooth = IsotropicSmooth(fwhm='4')

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/fsl/base.pyc in __init__(self, **inputs)
    160 
    161     def __init__(self, **inputs):
--> 162         super(FSLCommand, self).__init__(**inputs)
    163         self.inputs.on_trait_change(self._output_update, 'output_type')
    164 

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, command, **inputs)
   1563 
   1564     def __init__(self, command=None, **inputs):
-> 1565         super(CommandLine, self).__init__(**inputs)
   1566         self._environ = None
   1567         if not hasattr(self, '_cmd'):

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, **inputs)
    763             raise Exception('No input_spec in class: %s' %
    764                             self.__class__.__name__)
--> 765         self.inputs = self.input_spec(**inputs)
    766         self.estimated_memory_gb = 1
    767         self.num_threads = 1

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, **kwargs)
    360         # therefore these args were being ignored.
    361         # super(TraitedSpec, self).__init__(*args, **kwargs)
--> 362         super(BaseTraitedSpec, self).__init__(**kwargs)
    363         traits.push_exception_handler(reraise_exceptions=True)
    364         undefined_traits = {}

/opt/conda/envs/python2/lib/python2.7/site-packages/traits/trait_handlers.pyc in error(self, object, name, value)
    170         """
    171         raise TraitError( object, name, self.full_info( object, name, value ),
--> 172                           value )
    173 
    174     def full_info ( self, object, name, value ):

TraitError: The 'fwhm' trait of an IsotropicSmoothInput instance must be a float, but a value of '4' <type 'str'> was specified.

This will give you the error: TraitError: The 'fwhm' trait of an IsotropicSmoothInput instance must be a float, but a value of '4' <type 'str'> was specified.

To make sure that you are using the right input types, just check the help section of a given interface. There you can see fwhm: (a float).


In [ ]:
IsotropicSmooth.help()


Wraps command **fslmaths**

Use fslmaths to spatially smooth an image with a gaussian kernel.

Inputs::

	[Mandatory]
	fwhm: (a float)
		fwhm of smoothing kernel [mm]
		flag: -s %.5f, position: 4
		mutually_exclusive: sigma
	in_file: (an existing file name)
		image to operate on
		flag: %s, position: 2
	sigma: (a float)
		sigma of smoothing kernel [mm]
		flag: -s %.5f, position: 4
		mutually_exclusive: fwhm

	[Optional]
	args: (a string)
		Additional parameters to the command
		flag: %s
	environ: (a dictionary with keys which are a value of type 'str' and
		 with values which are a value of type 'str', nipype default value:
		 {})
		Environment variables
	ignore_exception: (a boolean, nipype default value: False)
		Print an error message instead of throwing an exception in case the
		interface fails to run
	internal_datatype: ('float' or 'char' or 'int' or 'short' or 'double'
		 or 'input')
		datatype to use for calculations (default is float)
		flag: -dt %s, position: 1
	nan2zeros: (a boolean)
		change NaNs to zeros before doing anything
		flag: -nan, position: 3
	out_file: (a file name)
		image to write
		flag: %s, position: -2
	output_datatype: ('float' or 'char' or 'int' or 'short' or 'double'
		 or 'input')
		datatype to use for output (default uses input type)
		flag: -odt %s, position: -1
	output_type: ('NIFTI_PAIR' or 'NIFTI_PAIR_GZ' or 'NIFTI_GZ' or
		 'NIFTI')
		FSL output type
	terminal_output: ('stream' or 'allatonce' or 'file' or 'none')
		Control terminal output: `stream` - displays to terminal immediately
		(default), `allatonce` - waits till command is finished to display
		output, `file` - writes output to file, `none` - output is ignored

Outputs::

	out_file: (an existing file name)
		image written after calculations

In a similar way, you will also get an error message if the input type is correct but you have a type in the name:

TraitError: The 'output_type' trait of an IsotropicSmoothInput instance must be u'NIFTI_PAIR' or u'NIFTI_PAIR_GZ' or u'NIFTI_GZ' or u'NIFTI', but a value of 'NIFTIiii' <type 'str'> was specified.

In [ ]:
from nipype.interfaces.fsl import IsotropicSmooth
smooth = IsotropicSmooth(output_type='NIFTIiii')


---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-5-d47a236310af> in <module>()
      1 from nipype.interfaces.fsl import IsotropicSmooth
----> 2 smooth = IsotropicSmooth(output_type='NIFTIiii')

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/fsl/base.pyc in __init__(self, **inputs)
    160 
    161     def __init__(self, **inputs):
--> 162         super(FSLCommand, self).__init__(**inputs)
    163         self.inputs.on_trait_change(self._output_update, 'output_type')
    164 

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, command, **inputs)
   1563 
   1564     def __init__(self, command=None, **inputs):
-> 1565         super(CommandLine, self).__init__(**inputs)
   1566         self._environ = None
   1567         if not hasattr(self, '_cmd'):

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, **inputs)
    763             raise Exception('No input_spec in class: %s' %
    764                             self.__class__.__name__)
--> 765         self.inputs = self.input_spec(**inputs)
    766         self.estimated_memory_gb = 1
    767         self.num_threads = 1

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, **kwargs)
    360         # therefore these args were being ignored.
    361         # super(TraitedSpec, self).__init__(*args, **kwargs)
--> 362         super(BaseTraitedSpec, self).__init__(**kwargs)
    363         traits.push_exception_handler(reraise_exceptions=True)
    364         undefined_traits = {}

/opt/conda/envs/python2/lib/python2.7/site-packages/traits/trait_handlers.pyc in error(self, object, name, value)
    170         """
    171         raise TraitError( object, name, self.full_info( object, name, value ),
--> 172                           value )
    173 
    174     def full_info ( self, object, name, value ):

TraitError: The 'output_type' trait of an IsotropicSmoothInput instance must be 'NIFTI_PAIR' or 'NIFTI_PAIR_GZ' or 'NIFTI_GZ' or 'NIFTI', but a value of 'NIFTIiii' <type 'str'> was specified.

Example Crash 3: Giving an array as input where a single file is expected

As you an see in the MapNode example, if you try to feed an array as an input into a field that only expects a single file, you will get a TraitError.


In [ ]:
from nipype.algorithms.misc import Gunzip
from nipype.pipeline.engine import Node

files = ['/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz',
         '/data/ds102/sub-01/func/sub-01_task-flanker_run-2_bold.nii.gz']

gunzip = Node(Gunzip(), name='gunzip',)
gunzip.inputs.in_file = files


---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-6-97767e4114d8> in <module>()
      6 
      7 gunzip = Node(Gunzip(), name='gunzip',)
----> 8 gunzip.inputs.in_file = files

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/traits_extension.pyc in validate(self, object, name, value)
     72             Note: The 'fast validator' version performs this check in C.
     73         """
---> 74         validated_value = super(BaseFile, self).validate(object, name, value)
     75         if not self.exists:
     76             return validated_value

/opt/conda/envs/python2/lib/python2.7/site-packages/traits/trait_types.pyc in validate(self, object, name, value)
    347             return value
    348 
--> 349         self.error( object, name, value )
    350 
    351     def create_editor ( self ):

/opt/conda/envs/python2/lib/python2.7/site-packages/traits/trait_handlers.pyc in error(self, object, name, value)
    170         """
    171         raise TraitError( object, name, self.full_info( object, name, value ),
--> 172                           value )
    173 
    174     def full_info ( self, object, name, value ):

TraitError: The 'in_file' trait of a GunzipInputSpec instance must be an existing file name, but a value of ['/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz', '/data/ds102/sub-01/func/sub-01_task-flanker_run-2_bold.nii.gz'] <type 'list'> was specified.

This can be solved by using a MapNode:


In [ ]:
from nipype.pipeline.engine import MapNode
gunzip = MapNode(Gunzip(), name='gunzip', iterfield=['in_file'])
gunzip.inputs.in_file = files

Now, make sure that you specify files that actually exist, otherwise you can the same problem as in crash example 1, but this time labeled as TraitError:

TraitError: Each element of the 'in_file' trait of a DynamicTraitedSpec instance must be an existing file name, but a value of '/data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz' <type 'str'> was specified.

In [ ]:
files = ['/data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz',
         '/data/ds102/sub-06/func/sub-06_task-flanker_run-2_bold.nii.gz']
gunzip.inputs.in_file = files


---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-8-b897be63be00> in <module>()
      1 files = ['/data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz',
      2          '/data/ds102/sub-06/func/sub-06_task-flanker_run-2_bold.nii.gz']
----> 3 gunzip.inputs.in_file = files

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in validate(self, object, name, value)
   1974                 isinstance(value[0], list)):
   1975             newvalue = [value]
-> 1976         value = super(MultiPath, self).validate(object, name, newvalue)
   1977 
   1978         if len(value) > 0:

/opt/conda/envs/python2/lib/python2.7/site-packages/traits/trait_types.pyc in validate(self, object, name, value)
   2335                 return value
   2336 
-> 2337             return TraitListObject( self, object, name, value )
   2338 
   2339         self.error( object, name, value )

/opt/conda/envs/python2/lib/python2.7/site-packages/traits/trait_handlers.pyc in __init__(self, trait, object, name, value)
   2311             except TraitError, excp:
   2312                 excp.set_prefix( 'Each element of the' )
-> 2313                 raise excp
   2314 
   2315         self.len_error( len( value ) )

TraitError: Each element of the 'in_file' trait of a DynamicTraitedSpec instance must be an existing file name, but a value of '/data/ds102/sub-06/func/sub-06_task-flanker_run-1_bold.nii.gz' <type 'str'> was specified.

By the way, not that those crashes don't create a crashfile, because they didn't happen during runtime, but still during workflow building.

Example Crash 4: SPM doesn't like *.nii.gz files

SPM12 cannot handle compressed NIfTI files (*nii.gz). If you try to run the node nonetheless, it can give you different kind of problems:

SPM Problem 1 with *.nii.gz files

SPM12 has a problem with handling *.nii.gz files. For it a compressed functional image has no temporal dimension and therefore seems to be just a 3D file. So if we try to run the Realign interface on a compressed file, we will get a weired UnicodeEncodeError error.


In [ ]:
from nipype.interfaces.spm import Realign
realign = Realign(in_files='/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz')
realign.run()


---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in run_code(self, code_obj, result)
   2896             if result is not None:
   2897                 result.error_in_exec = sys.exc_info()[1]
-> 2898             self.showtraceback()
   2899         else:
   2900             outflag = 0

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in showtraceback(self, exc_tuple, filename, tb_offset, exception_only)
   1822                     except Exception:
   1823                         stb = self.InteractiveTB.structured_traceback(etype,
-> 1824                                             value, tb, tb_offset=tb_offset)
   1825 
   1826                     self._showtraceback(etype, value, stb)

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/ultratb.pyc in structured_traceback(self, etype, value, tb, tb_offset, number_of_lines_of_context)
   1410         self.tb = tb
   1411         return FormattedTB.structured_traceback(
-> 1412             self, etype, value, tb, tb_offset, number_of_lines_of_context)
   1413 
   1414 

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/ultratb.pyc in structured_traceback(self, etype, value, tb, tb_offset, number_of_lines_of_context)
   1318             # Verbose modes need a full traceback
   1319             return VerboseTB.structured_traceback(
-> 1320                 self, etype, value, tb, tb_offset, number_of_lines_of_context
   1321             )
   1322         else:

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/ultratb.pyc in structured_traceback(self, etype, evalue, etb, tb_offset, number_of_lines_of_context)
   1168 
   1169         formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
-> 1170                                                                tb_offset)
   1171 
   1172         colors = self.Colors  # just a shorthand + quicker name lookup

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/ultratb.pyc in format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset)
   1111             return ""
   1112 
-> 1113         last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
   1114 
   1115         frames = self.format_records(records, last_unique, recursion_repeat)

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/ultratb.pyc in find_recursion(etype, value, records)
    453     # quarter of the traceback (250 frames by default) is repeats, and find the
    454     # first frame (from in to out) that looks different.
--> 455     if not is_recursion_error(etype, value, records):
    456         return len(records), 0
    457 

/opt/conda/envs/python2/lib/python2.7/site-packages/IPython/core/ultratb.pyc in is_recursion_error(etype, value, records)
    439     # a recursion error.
    440     return (etype is recursion_error_type) \
--> 441            and "recursion" in str(value).lower() \
    442            and len(records) > 500
    443 

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf7' in position 2008: ordinal not in range(128)

But what does this UnicodeEncodeError mean?

UnicodeEncodeError: 'ascii' codec can't encode character u'\xf7' in position 7984: ordinal not in range(128)

Well, to find out, we need to dig a bit deeper and check the corresponding MATLAB script. Because every SPM interface creates an executable MATLAB script, either in the current location or in the folder of the node. So what's written in this script?


In [ ]:
!cat /home/jovyan/work/notebooks/pyscript_realign.m


fprintf(1,'Executing %s at %s:\n',mfilename(),datestr(now));
ver,
try,
        %% Generated by nipype.interfaces.spm
        if isempty(which('spm')),
             throw(MException('SPMCheck:NotFound', 'SPM not in matlab path'));
        end
        [name, version] = spm('ver');
        fprintf('SPM version: %s Release: %s\n',name, version);
        fprintf('SPM path: %s\n', which('spm'));
        spm('Defaults','fMRI');

        if strcmp(name, 'SPM8') || strcmp(name(1:5), 'SPM12'),
           spm_jobman('initcfg');
           spm_get_defaults('cmdline', 1);
        end

        jobs{1}.spm.spatial.realign.estwrite.roptions.prefix = 'r';
jobs{1}.spm.spatial.realign.estwrite.roptions.which(1) = 2;
jobs{1}.spm.spatial.realign.estwrite.roptions.which(2) = 1;
jobs{1}.spm.spatial.realign.estwrite.data = {...
{...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,1';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,2';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,3';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,4';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,5';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,6';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,7';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,8';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,9';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,10';...
'...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,140';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,141';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,142';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,143';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,144';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,145';...
'/data/ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz,146';...
};
};

        spm_jobman('run', jobs);

        
        if strcmp(name, 'SPM8') || strcmp(name(1:5), 'SPM12'),
            close('all', 'force');
        end;
            
,catch ME,
fprintf(2,'MATLAB code threw an exception:\n');
fprintf(2,'%s\n',ME.message);
if length(ME.stack) ~= 0, fprintf(2,'File:%s\nName:%s\nLine:%d\n',ME.stack.file,ME.stack.name,ME.stack.line);, end;
end;

All seems to be fine, right? It even detects that the functional image has a temporal dimension. So what's wrong with MATLAB? To find out, let's run the script directly in matlab ourselves...


In [ ]:
!/opt/spm12/run_spm12.sh /opt/mcr/v91/ batch pyscript_realign.m


------------------------------------------
Setting up environment variables
---
LD_LIBRARY_PATH is .:/opt/mcr/v91//runtime/glnxa64:/opt/mcr/v91//bin/glnxa64:/opt/mcr/v91//sys/os/glnxa64:/opt/mcr/v91//sys/opengl/lib/glnxa64
SPM12 (6906): /opt/spm12/spm12_mcr/spm12
 ___  ____  __  __                                            
/ __)(  _ \(  \/  )                                           
\__ \ )___/ )    (   Statistical Parametric Mapping           
(___/(__)  (_/\/\_)  SPM12 - http://www.fil.ion.ucl.ac.uk/spm/

Executing spm_jobman at 01-Mar-2017 22:05:54:
----------------------------------------------------------------------------------------------------
MATLAB Version: 9.1.0.441655 (R2016b)
MATLAB License Number: unknown
Operating System: Linux 4.8.0-39-generic #42~16.04.1-Ubuntu SMP Mon Feb 20 15:06:07 UTC 2017 x86_64
Java Version: Java 1.7.0_60-b19 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
----------------------------------------------------------------------------------------------------
MATLAB                                                Version 9.1         (R2016b)
MATLAB                                                Version 9.1         (R2016b)
MATLAB Compiler                                       Version 6.3         (R2016b)
SPM version: SPM12 Release: 6906
SPM path: /opt/spm12/spm12_mcr/spm12/spm.m
Item 'Session', field 'val': Number of matching files (0) less than required (1).
MATLAB code threw an exception:
No executable modules, but still unresolved dependencies or incomplete module inputs.
File:/opt/spm12/spm12_mcr/spm12/spm_jobman.m
Name:/opt/spm12/spm12_mcr/spm12/spm_jobman.m
Line:47
File:opt/spm12/spm12_mcr/spm12/spm_jobman.m
Name:/opt/spm12/spm12_mcr/spm12/spm_jobman.m
Line:47
File:opt/spm12/spm12_mcr/spm12/spm_standalone.m
Name:fill_run_job
Line:115
File:pm_jobman
Name:load_jobs
Line:115
File:pm_jobman
Name:spm_standalone
Line:461
File:÷
Name:ʼn
Line:143Item 'Session', field 'val': Number of matching files (0) less than required (1).
Execution failed: pyscript_realign.mBye for now...


File:!
Name:

Now, here's at least a hint. At the end of the output, we get the following lines:

Item 'Session', field 'val': Number of matching files (0) less than required (1).
MATLAB code threw an exception:
No executable modules, but still unresolved dependencies or incomplete module inputs.

It's not too clear from the output, but MATLAB tries to tell you, that it cannot read the compressed NIfTI files. Therefore, it doesn't find one single NIfTI file (0 matching files, required 1).

Solve this issue by unzipping the compressed NIfTI file before giving it as an input to an SPM node. This can either be done by using the Gunzip interface from Nipype or even better, if the input is coming from a FSL interface, most of them have an input filed output_type='NIFTI', that you can set to NIFIT.

SPM problem 2 with *.nii.gz files

Even worse than the problem before, it might be even possible that SPM doesn't tell you at all what the problem is:


In [ ]:
from nipype.interfaces.spm import Smooth
smooth = Smooth(in_files='/data/ds102/sub-01/anat/sub-01_T1w.nii.gz')
smooth.run()


---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-12-ea7350622128> in <module>()
      1 from nipype.interfaces.spm import Smooth
      2 smooth = Smooth(in_files='/data/ds102/sub-01/anat/sub-01_T1w.nii.gz')
----> 3 smooth.run()

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in run(self, **inputs)
   1042         try:
   1043             runtime = self._run_wrapper(runtime)
-> 1044             outputs = self.aggregate_outputs(runtime)
   1045             runtime.endTime = dt.isoformat(dt.utcnow())
   1046             timediff = parseutc(runtime.endTime) - parseutc(runtime.startTime)

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in aggregate_outputs(self, runtime, needed_outputs)
   1136                         msg = ("File/Directory '%s' not found for %s output "
   1137                                "'%s'." % (val, self.__class__.__name__, key))
-> 1138                         raise FileNotFoundError(msg)
   1139                     else:
   1140                         raise error

FileNotFoundError: File/Directory '['/data/ds102/sub-01/anat/ssub-01_T1w.nii.gz']' not found for Smooth output 'smoothed_files'.
Interface Smooth failed to run. 

As you can see, in this case you'll get the error:

FileNotFoundError: File/Directory '[u'/data/workflow/smooth/ssub-01_T1w.nii.gz']' not found for Smooth output 'smoothed_files'.
Interface Smooth failed to run.

It's easy to overlook the additional s in front of the file name. The problem is, the error tells you that it cannot find the output file of smooth, but doesn't tell you what the problem in MATLAB was.

And even if you run the MATLAB script yourself, you will get no hints. In this case, good luck...

...
------------------------------------------------------------------------
Running job #1
------------------------------------------------------------------------
Running 'Smooth'
Done    'Smooth'
Done

In [ ]:
!/opt/spm12/run_spm12.sh /opt/mcr/v91/ batch pyscript_smooth.m


------------------------------------------
Setting up environment variables
---
LD_LIBRARY_PATH is .:/opt/mcr/v91//runtime/glnxa64:/opt/mcr/v91//bin/glnxa64:/opt/mcr/v91//sys/os/glnxa64:/opt/mcr/v91//sys/opengl/lib/glnxa64
SPM12 (6906): /opt/spm12/spm12_mcr/spm12
 ___  ____  __  __                                            
/ __)(  _ \(  \/  )                                           
\__ \ )___/ )    (   Statistical Parametric Mapping           
(___/(__)  (_/\/\_)  SPM12 - http://www.fil.ion.ucl.ac.uk/spm/

Executing spm_jobman at 01-Mar-2017 22:07:12:
----------------------------------------------------------------------------------------------------
MATLAB Version: 9.1.0.441655 (R2016b)
MATLAB License Number: unknown
Operating System: Linux 4.8.0-39-generic #42~16.04.1-Ubuntu SMP Mon Feb 20 15:06:07 UTC 2017 x86_64
Java Version: Java 1.7.0_60-b19 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
----------------------------------------------------------------------------------------------------
MATLAB                                                Version 9.1         (R2016b)
MATLAB                                                Version 9.1         (R2016b)
MATLAB Compiler                                       Version 6.3         (R2016b)
SPM version: SPM12 Release: 6906
SPM path: /opt/spm12/spm12_mcr/spm12/spm.m


------------------------------------------------------------------------
Running job #1
------------------------------------------------------------------------
Running 'Smooth'
Done    'Smooth'
Done


Example Crash 5: Nipype cannot find the right software

Especially at the beginning, just after installation, you sometimes forgot to specify some environment variables. If you try to use an interface where the environment variables of the software are not specified, you'll errors, such as:

IOError: command 'mri_convert' could not be found on host mnotter
Interface MRIConvert failed to run.

In [ ]:
from nipype.interfaces.freesurfer import MRIConvert
convert = MRIConvert(in_file='/data/ds102/sub-01/anat/sub-01_T1w.nii.gz',
                     out_type='nii')

Or if you try to use SPM, but forgot to tell Nipype where to find it. If you forgot to tell the system where to find MATLAB (or MCR), than you will get same kind of error as above. But if you forgot to specify which SPM you want to use, you'll get the following RuntimeError:

Standard error:
MATLAB code threw an exception:
SPM not in matlab path


You can solve this issue by specifying the path to your SPM version:

from nipype.interfaces.matlab import MatlabCommand
MatlabCommand.set_default_paths('/usr/local/MATLAB/R2017a/toolbox/spm12')

Example Crash 6: You forget mandatory inputs or use input fields that don't exist

One of the simpler errors are the ones connected to input and output fields.

Forgetting mandatory input fields

Let's see what happens if you forget a [Mandatory] input field.


In [ ]:
from nipype.interfaces.spm import Realign
realign = Realign(register_to_mean=True)
realign.run()


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-17-29d156abbd26> in <module>()
      1 from nipype.interfaces.spm import Realign
      2 realign = Realign(register_to_mean=True)
----> 3 realign.run()

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in run(self, **inputs)
   1026         """
   1027         self.inputs.set(**inputs)
-> 1028         self._check_mandatory_inputs()
   1029         self._check_version_requirements(self.inputs)
   1030         interface = self.__class__

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in _check_mandatory_inputs(self)
    938                        "For a list of required inputs, see %s.help()" %
    939                        (self.__class__.__name__, name, self.__class__.__name__))
--> 940                 raise ValueError(msg)
    941             if isdefined(value):
    942                 self._check_requires(spec, name, value)

ValueError: Realign requires a value for input 'in_files'. For a list of required inputs, see Realign.help()

This gives you the error:

ValueError: Realign requires a value for input 'in_files'. For a list of required inputs, see Realign.help()

As described by the error text, if we use the help() function, we can actually see, which inputs are mandatory and which are optional.


In [ ]:
realign.help()


Use spm_realign for estimating within modality rigid body alignment

http://www.fil.ion.ucl.ac.uk/spm/doc/manual.pdf#page=25

Examples
--------

>>> import nipype.interfaces.spm as spm
>>> realign = spm.Realign()
>>> realign.inputs.in_files = 'functional.nii'
>>> realign.inputs.register_to_mean = True
>>> realign.run() # doctest: +SKIP

Inputs::

	[Mandatory]
	in_files: (a list of items which are a list of items which are an
		 existing file name or an existing file name)
		list of filenames to realign

	[Optional]
	fwhm: (a floating point number >= 0.0)
		gaussian smoothing kernel width
	ignore_exception: (a boolean, nipype default value: False)
		Print an error message instead of throwing an exception in case the
		interface fails to run
	interp: (0 <= an integer <= 7)
		degree of b-spline used for interpolation
	jobtype: ('estwrite' or 'estimate' or 'write', nipype default value:
		 estwrite)
		one of: estimate, write, estwrite
	matlab_cmd: (a string)
		matlab command to use
	mfile: (a boolean, nipype default value: True)
		Run m-code using m-file
	out_prefix: (a string, nipype default value: r)
		realigned output prefix
	paths: (a list of items which are a directory name)
		Paths to add to matlabpath
	quality: (0.0 <= a floating point number <= 1.0)
		0.1 = fast, 1.0 = precise
	register_to_mean: (a boolean)
		Indicate whether realignment is done to the mean image
	separation: (a floating point number >= 0.0)
		sampling separation in mm
	use_mcr: (a boolean)
		Run m-code using SPM MCR
	use_v8struct: (a boolean, nipype default value: True)
		Generate SPM8 and higher compatible jobs
	weight_img: (an existing file name)
		filename of weighting image
	wrap: (a list of from 3 to 3 items which are an integer (int or
		 long))
		Check if interpolation should wrap in [x,y,z]
	write_interp: (0 <= an integer <= 7)
		degree of b-spline used for interpolation
	write_mask: (a boolean)
		True/False mask output image
	write_which: (a list of items which are a value of type 'int', nipype
		 default value: [2, 1])
		determines which images to reslice
	write_wrap: (a list of from 3 to 3 items which are an integer (int or
		 long))
		Check if interpolation should wrap in [x,y,z]

Outputs::

	mean_image: (an existing file name)
		Mean image file from the realignment
	modified_in_files: (a list of items which are a list of items which
		 are an existing file name or an existing file name)
		Copies of all files passed to in_files. Headers will have been
		modified to align all images with the first, or optionally to first
		do that, extract a mean image, and re-align to that mean image.
	realigned_files: (a list of items which are a list of items which are
		 an existing file name or an existing file name)
		If jobtype is write or estwrite, these will be the resliced files.
		Otherwise, they will be copies of in_files that have had their
		headers rewritten.
	realignment_parameters: (a list of items which are an existing file
		 name)
		Estimated translation and rotation parameters

Using input fields that don't exist

Let's see what happens if we try to specify a parameter that doesn't exist as an input field:


In [ ]:
from nipype.interfaces.afni import Despike
despike = Despike(in_file='../../ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz',
                  output_type='NIFTI')
despike.run()


---------------------------------------------------------------------------
TraitError                                Traceback (most recent call last)
<ipython-input-19-bc608a453fb3> in <module>()
      1 from nipype.interfaces.afni import Despike
      2 despike = Despike(in_file='../../ds102/sub-01/func/sub-01_task-flanker_run-1_bold.nii.gz',
----> 3                   output_type='NIFTI')
      4 despike.run()

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/afni/base.pyc in __init__(self, **inputs)
    148 
    149     def __init__(self, **inputs):
--> 150         super(AFNICommand, self).__init__(**inputs)
    151         self.inputs.on_trait_change(self._output_update, 'outputtype')
    152 

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, command, **inputs)
   1563 
   1564     def __init__(self, command=None, **inputs):
-> 1565         super(CommandLine, self).__init__(**inputs)
   1566         self._environ = None
   1567         if not hasattr(self, '_cmd'):

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, **inputs)
    763             raise Exception('No input_spec in class: %s' %
    764                             self.__class__.__name__)
--> 765         self.inputs = self.input_spec(**inputs)
    766         self.estimated_memory_gb = 1
    767         self.num_threads = 1

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/interfaces/base.pyc in __init__(self, **kwargs)
    360         # therefore these args were being ignored.
    361         # super(TraitedSpec, self).__init__(*args, **kwargs)
--> 362         super(BaseTraitedSpec, self).__init__(**kwargs)
    363         traits.push_exception_handler(reraise_exceptions=True)
    364         undefined_traits = {}

TraitError: Cannot set the undefined 'output_type' attribute of a 'DespikeInputSpec' object.

This results in the TraitError:

TraitError: Cannot set the undefined 'output_type' attribute of a 'DespikeInputSpec' object.

So what went wrong? If you use the help() function, you will see that the correct input filed is called outputtype and not output_type.

Example Crash 7: Trying to connect a node to an input field that is already occupied

Sometimes when you build a new workflow, you might forget that an output field was already connected and you try to connect a new node to the already occupied field.

First, let's create a simple workflow:


In [ ]:
from nipype import SelectFiles, Node, Workflow
from os.path import abspath as opap
from nipype.interfaces.fsl import MCFLIRT, IsotropicSmooth

# Create SelectFiles node
templates={'func': '{subject_id}/func/{subject_id}_task-flanker_run-1_bold.nii.gz'}
sf = Node(SelectFiles(templates),
          name='selectfiles')
sf.inputs.base_directory = opap('/data/ds102')
sf.inputs.subject_id = 'sub-01'

# Create Motion Correction Node
mcflirt = Node(MCFLIRT(mean_vol=True,
                       save_plots=True),
               name='mcflirt')

# Create Smoothing node
smooth = Node(IsotropicSmooth(fwhm=4),
              name='smooth')

# Create a preprocessing workflow
wf = Workflow(name="preprocWF")
wf.base_dir = 'working_dir'

# Connect the three nodes to each other
wf.connect([(sf, mcflirt, [("func", "in_file")]),
            (mcflirt, smooth, [("out_file", "in_file")])])

Now, let's create a new node and connect it to the already occupied input field in_file of the smooth node:


In [ ]:
# Create a new node
mcflirt_NEW = Node(MCFLIRT(mean_vol=True),
                   name='mcflirt_NEW')

# Connect it to an already connected input field
wf.connect([(mcflirt_NEW, smooth, [("out_file", "in_file")])])


---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-21-10d23e4325e2> in <module>()
      4 
      5 # Connect it to an already connected input field
----> 6 wf.connect([(mcflirt_NEW, smooth, [("out_file", "in_file")])])

/opt/conda/envs/python2/lib/python2.7/site-packages/nipype/pipeline/engine/workflows.pyc in connect(self, *args, **kwargs)
    215 Trying to connect %s:%s to %s:%s but input '%s' of node '%s' is already
    216 connected.
--> 217 """ % (srcnode, source, destnode, dest, dest, destnode))
    218                 if not (hasattr(destnode, '_interface') and
    219                         '.io' in str(destnode._interface.__class__)):

Exception: 
Trying to connect preprocWF.mcflirt_NEW:out_file to preprocWF.smooth:in_file but input 'in_file' of node 'preprocWF.smooth' is already
connected.

This will lead to the error:

Exception: 
Trying to connect preprocWF.mcflirt_NEW:out_file to preprocWF.smooth:in_file but input 'in_file' of node 'preprocWF.smooth' is already connected.