Slicer crash when saving scene with processed Sequence data

Hello, I am having a reproducible crash of Slicer when I try to save a scene. I have a sequence of 3D volumes and have done several processing steps on them, and have saved that progress in an mrb file. Then I do a bit more processing, and then when I try to save the scene, Slicer crashes. A _BundleSaveTemp directory is created and it contains in incomplete MRML file (no XML closing MRML tag, and no closing tag for a vtkMRMLScriptedModuleNodeUserStatistics ScriptedModule). I believe there is likely also a lot more missing which would appear after that, because if I just remove that last ScriptedModule section and manually add the </MRML> tag and then try to load that mrml file, I get many errors which say ResolveUnresolvedItems: Unable to find data node with ID (nullptr). I can consistently reproduce this crash by following the same steps, but I’m not sure what the best approach to troubleshooting would be. There is nothing at the end of the error logs (the last message logged is before I click save; for example, [DEBUG][Qt] 21.05.2021 16:41:05 [] (unknown:0) - Switch to module: "Data"), so there’s nothing helpful there.

Is the fact that the MRML scene file is truncated a good hint? Is the problem likely related to the UserStatistics module (which I make no use of at this point, if I look at it the “Enabled” checkbox is unchecked) because that is where the .mrml file cuts off?

Other suggestions about how to troubleshoot crashes? I’m using a custom module that is doing a lot of node management on Sequences, and I feel like sometimes the code manages to get the SubjectHierarchy confused, but I don’t really understand how it happens, and it doesn’t seem consistent. This is the first time I have ever run into not being able to save a scene to an mrb file.

Probably the best way to approach this is to do start with a workflow that doesn’t crash and incrementally add features until you can isolate what leads to the corruption. As you say, it’s probably the node references or subject hierarchy getting out of sync. The fact that you have the half-written mrml file indicates that one of the storage nodes crashed during the save process.

You could also do a debug build from source and use the debugger to identify where the crash is happening in C++. There’s a chance this would isolate the error, but probably the actual bug is somewhere else and the mrml scene is already in a corrupt state by the time you want to save.

1 Like

I am making progress on this problem, and it occurs earlier than I thought. I wonder if I am creating derived Sequences in the wrong way. Currently, I have been creating them via

seq = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSequenceNode')

which is the way I create all sorts of other classes of MRML nodes, but I see that the following error message appears when I open the Save Data dialog after creating a Sequence node in this way:

void __cdecl qSlicerSaveDataDialogPrivate::populateNode(class vtkMRMLNode *)  failed: 
storage node not found for node  vtkMRMLSequenceNode2 . The node will not be shown in the 
save data dialog.

Calling seq.CreateDefaultStorageNode() or seq.CreateDefaultSequenceStorageNode() doesn’t seem to help; I get the same error after running them.

Checking an existing Sequence (that I didn’t create), I see that the storage node is of type vtkMRMLVolumeSequenceStorageNode, which got me looking through the Slicer source code for the Sequences module, where I see a storage node being set up in a function called AddSequence(), but maybe that’s for loading a Sequence from a file? I also see a function called AddSynchronizedNode() which looks like maybe I should be using that for creating the sequences I want instead of mrmlScene.AddNewNodeByClass()? It looks like it can handle a null sequence argument.

Taking a step back, I have a volume sequence with an associated sequence browser. My goal is to end up with a new volume sequence associated with the same browser, where the volumes in the new sequence are derived by processing the volumes in the existing volume sequence. What is the correct way to do this in general? My approach so far has been to create a new Sequence, fill it, and then use browserNode.AddSynchronizedSequenceNode() to add the new Sequence to the existing browser. I assumed I needed to do this because I thought an empty or partially filled sequence would not be able to be added to the browser node (because how would you handle browsing through one sequence with 14 items and another with 3 items?), but perhaps I am incorrect?

Found the step that leads to the crash. Here is a minimal example using SampleData which reproduces the crash:

import SampleData    
sequenceNode = SampleData.downloadSample('CTCardioSeq')
sequenceBrowserNode = slicer.modules.sequences.logic().GetFirstBrowserNodeForSequenceNode(sequenceNode)
newSeq = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSequenceNode')
# this is the change that causes the crash:
sequenceBrowserNode.SetSaveChanges(newSeq,True) 
sceneSaveFilename = slicer.app.temporaryPath + "/saved-scene-crashes.mrb" 
# crash occurs while executing this line:
slicer.util.saveScene(sceneSaveFilename)

This seems like a bug. I am later going to fill the sequences I create using SetDataNodeAtValue(), and I wasn’t sure whether I needed to set save changes to True in order for those additions to be recorded in the sequence (and I figured it couldn’t hurt even if it wasn’t necessary), which is why I had set “Save Changes” to True for these sequences. I’ll try not setting it that way.

Just noticed that my crash example code is missing the line

sequenceBrowserNode.AddSynchronizedSequenceNode(newSeq)

With this line included, there is no crash. So, the issue in that case is probably related to setting SaveChanges on a sequence which isn’t actually associated with the browser node. This still seems like a bug, but maybe a less severe one.

1 Like

Thank you, the detailed instructions for reproducing the problem were very helpful.

The crash was caused by the sequence browser getting into an inconsistent state due to incorrect use of the API (invoking operation on a browser node for an unrelated sequence node). The issue is fixed by checking the inputs and displaying meaningful error message if they are invalid.

1 Like