Causes of CTDs
Crashes to desktop (CTDs) can be difficult to track down, this page describes methods of debugging, and potential causes and workarounds.
Much of the information on this page should be viewed as just worthwhile lines of investigation when debugging, sourced from personal experiences, not as proven causes.
- 1 Debugging
- 2 Script Errors
- 2.1 Infinite loops
- 2.2 Invalid references
- 2.3 Some functions are not instant to effect
- 2.4 BuildRef might not return what you expect
- 2.5 Unexpected returns during immediate game start up
- 2.6 Invalid string formatting
- 2.7 Invalid And/Or syntax for conditions
- 2.8 NPC outfit scripts that modify inventory
- 2.9 Removing an object whilst its script is in progress
- 2.10 Nested function calls
- 2.11 Single line And/Or conditions
- 2.12 Incorrect trigger blocks
- 3 Animations
- 4 Worldspace Navmeshes
- 5 Tree LOD
- 6 NIFs
The console command SCOF can be used in game, or via a script with Con_SCOF to write all console output to a text file in the fallout game directory. This is very useful as it allows you to trace output to the point of CTD back in Windows. Auto SCOF is a mod to automatically create a console output file on game load.
; within game console, type: scof "mydebuglog.txt"
If NVSE is installed you can enable additional debug messages.
; within game console, type: SetConsoleEcho 1
The most common cause of CTDs is probably infinite loops, caused when a loop condition never becomes false. With NVSE, it is good practise to replace all usage of Label with Foreach or While. Where possible, putting condition modifiers at the beginning of the loop is recommended, to avoid them potentially being skipped by conditional usage of Continue or Goto. Indentation of any loop block is highly recommended.
Looping quest stages may also be potentially non-terminating.
Some functions may cause a CTD if run on an invalid reference, such as a ref variable which is empty, contains a base form, or is non-persistent and non-loaded. This may be avoided by checking the variable contents with a condition, such as IsReference, IsFormValid, TypeOf, GetType.
ref MyRef if IsReference MyRef ; safe to proceed, MyRef is valid reference endif
To catch empty ref variables, you can do just:
But, this will not catch base forms if you need a reference.
Some functions are not instant to effect
Some functions, particularly those that modify the 3D world, do not necessarily take effect instantly, they can potentially take several (an unpredictable number) of frames to complete. This can result in the invalid reference situation described above. For example:
set FirstRef to PlayerREF.PlaceAtMe Something SecondRef.MoveTo FirstRef FirstRef.Disable FirstRef.MarkForDelete
Note also that RemoveMe and Dispel are not instant, and a script may run for several frames after its parent object/spell was removed, with unpredictable behavior. To protect against this, you can use:
int Completed Begin GameMode if Completed return endif ; * do something set Completed to 1 RemoveMe End
BuildRef might not return what you expect
The BuildRef function allows you to reference assets of an external mod without making that mod a master to your own plugin. However, it can potentially return an invalid or unexpected reference, and crash the game if you do not bother to check for this. See the BuildRef function article for full details.
Unexpected returns during immediate game start up
It has been observed on a few occasions where scripts running in early game startup, or sometimes just on their first scan return <NULL> for an actor. With all the DLC's booting up, I've experienced such failures up to 10 seconds after gamestart, things like a female player returning zero for GetIsSex Female.
Invalid string formatting
Using invalid format specifiers or mismatched number of arguments to format may crash the game (and at best the script), for example:
DebugPrint "GunScript %n: Shooting %2.0 bullets" rActor iBullets ; you meant "%2.0f" but missed the f
Invalid And/Or syntax for conditions
Invalid And/Or syntax will still compile, but will crash the script and possibly the game when it runs, for example:
if A==B && D < 1 && && W >= 7 ; above ;
This comes from my personal experience. Sometimes absurd wrong syntax compile (so never fully trust 100% the compiler or PU). But mainly, some of them don't CTD in game and silently break the script execution, making the debug pretty hard.
Here an example, a mistake I did more than once because of copy/paste:
if (something) || (something else) || (some other thing) ||
(I left an extra || at the end) - This line was compiling, but it wasn't CTD in game, it was interrupting the rest of the script from that line to the end. I use vanilla + 4Gb + NVSE + PU, so it's not like NVAC preventing CTD or whatever. Also I noticed how some script mistakes CTD in FO3, while don't CTD in NV but they interrupt the script execution. And not because of FOSE / NVSE, I'm talking about vanilla script.
NPC outfit scripts that modify inventory
If you get an object script attached to an outfit worn by an NPC to add or remove any item from that NPC, it can cause a CTD. It's not an immediate CTD, you get funny colors & sounds, it's CTD on Drugs, and for other items sometimes just game freezes. Exactly the same script works fine on the Player though. I found this in doing damaged armor swapping- the only way to get it to work was have the token cast a scripted effect, with the effect script allowing adding or removing of items without crashing.
Removing an object whilst its script is in progress
If you have an object whose script calls a User Defined Function, and that UDF removes the object this will cause a CTD. This may be because the calling script for the UDF has been destroyed with its parent object, so its execution can not continue following the UDF call. It is better to use RemoveMe within the object's script, based on a return value for the function.
Nested function calls
If using the Script Compiler Override, it is possible to nest multiple function calls on a single line, rather than use intermediary variables. Sometimes this causes a CTD, which is avoidable by using multiple lines.
Single line And/Or conditions
Using And/Or (&& / ||) to evaluate too many conditions on a single line has been noted to cause a CTD when testing multiple UDFs or NVSE string comparisons. Separating the condition into multiple lines, or changing to a single UDF call, which itself checks all the conditions on single lines works around this.
Note also that the GECK does not short circuit and/or conditions when they become proven, all conditions on the line are always evaluated.
Incorrect trigger blocks
Using OnTrigger in trigger boxes instead of OnTriggerEnter can cause infinite loops.
This is not about scripting, but still a cause of CTD, I would say it's common among users. When a .kf (animation file) calls a movement on a bone which is not present in the skeleton, this usually leads to a CTD. However you don't need to have a body /armor rigged on that bone, to avoid it, only have the right skeleton. This is the reason why in many mods the modders want you to install a compatibility skeleton, because it has all the possible bones used among different mods.
Animations - Textdatas
Curious to notice how an empty (wrong) textdata could lead to a GECK CTD when it's previewed on the render window, but it will be ignored in game and will work fine.
Having uncaught errors in a navmesh that is in an exterior location can cause CTD on load of any save. This effect can be delayed by up to nearly a minute in some cases. It is also possible for this to happen if you manipulated an error free navmesh and forgot to finalize it.
This may be due to bad navmesh info and can sometimes be fixed by deleting the navmesh infos for your exteriors in FO3Edit and letting GECK re generate them. It is unknown if this creates other issues but it has been observed to resolve CTD on load without creating any additional GECK errors and does not require physically recreating your actual navmesh.
Deleting navmeshes can cause CTD's particularly when another mod has added door links to a triangle in the deleted navmesh. It is important to circumvent this bug in xEdit by removing the deleted navmesh from the overriding plugin and renumbering the formid of the new navmesh to that of the deleted one. In such case that the navmesh has merged more than one navmesh into a single one and deleted several navmeshes, you can use the "move to separate navmesh" option in GECK to separate the navmesh back into parts without breaking it's functionality. You can then renumber the formids to those of the deleted navmeshes after removal of them. It is also important to reload the plugin into GECK after editing them and re-finalize them to fix any door links in both the exterior cell(s) and the connected interior cell(s).
Disabling trees with tree LOD will cause a CTD. Move them under the ground instead.
There are a multitude of things which can cause a CTD in NIFs.
- Invalid MOPP data in a havok collision. This is a long standing issue with a bug in nifskope and in the niftools plugins that was fixed in 2017, seek out help on the nifskope discord for a working MOPP generator.
- Bad weight painting
- Bad skinning
- Invalid animation data or Extra Target table
- Invalid shader flags
- Non-power of 2 textures
- Bad contraints
- Wrong or missing havok target node
- Incorrect block order
- Incorrect Havok data
- NiTriStrips before NiNodes
- Wrong order of bhkOrientHingedBodyAction
- Having a BSFadeNode instead of a NiNode root in rigged objects
Check nifs carefully, just because they work in GECK preview doesn't mean they work properly in game.