Causes of CTDs

From GECK
Jump to: navigation, search

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.

Debugging

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

Script Errors

Infinite loops

The most common cause of CTDs is probably infinite loops, caused when a loop condition never becomes false. With NVSE, it is good practice 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.

Invalid references

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 IsFormValid MyRef != 1
   return  ; MyRef is not a valid form (neither a Reference nor an Object).
elseif IsReference MyRef
  ; safe to proceed, MyRef is valid reference
endif

To catch empty ref variables, you can do just:

if MyRef

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

If using NVSE, it is safer to use string concatanation and the ToString function where possible, instead of formatting. See String Variable for more information.

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. Eval does have a short-circuit logic in new versions of xNVSE.

Incorrect trigger blocks

Using OnTrigger in trigger boxes instead of OnTriggerEnter can cause infinite loops.

MarkForDelete

MarkForDelete can cause a crash if used with Inventory References, particularly if used to attempt to delete Items with OnAdd blocks. Use RemoveMeIRAlt instead to delete inventory references.

Animations

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.

Worldspace Navmeshes

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).

Tree LOD

Disabling trees with Tree LOD will cause a CTD. Move them under the ground instead.

NIFs

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, use SNIFF to batch update MOPP in your NIFs.
  • Bad weight painting
  • Bad skinning
  • Invalid animation data or Extra Target table
  • Invalid shader flags
  • Non-power of 2 textures
  • Bad constraints
  • Wrong or missing Havok target node
  • Incorrect block order (such as a bhkCollisionObject ordered after geometry or NiNodes)
  • Incorrect Havok data
  • NiTriStrips before NiNodes
  • Wrong order of bhkOrientHingedBodyAction
  • Having a NiSpecularProperty (some plugins don't know what to do with them and CTD upon taking or equipping items with them)
  • 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.

Formlists

If a record in a formlist is being referenced that doesn't actually exist because of having being removed from the files (seen as a "error could not be resolved" list entry when viewing them in xEdit) this may cause the game to hang at startup with you being unable to play the game at all. Use XEdit to check your mod for errors and it will report invalid entries in formlists.

See Also