Skip to main content

Troubleshooting

A complete guide to diagnosing and resolving errors in the StoryFlow Unreal Engine plugin. Covers every runtime error message, debugging techniques, and common solutions.

Error Handling Overview

The StoryFlow plugin reports errors through two channels:

OnError Delegate

A BlueprintAssignable delegate on UStoryFlowComponent. Bind to this in Blueprint or C++ to handle errors in your game - for example, showing a message to the player or logging to your own system.

Output Log

All errors are also logged via UE_LOG(LogStoryFlow, Error, ...). Open the Output Log panel in the Unreal Editor and filter by "StoryFlow" to see all plugin messages.

Errors Are Non-Fatal

StoryFlow errors do not crash your game. When an error occurs, the runtime stops processing the current node chain and fires OnError. Dialogue execution may end or stall, but your game continues running. This lets you handle errors gracefully in your UI.

Warnings vs Errors

Forward-compatibility messages from the runtime (described in Forward Compatibility Warnings) are logged at Warning level only. They go through LogStoryFlow but do not invoke the OnError delegate. Execution continues past the unsupported node so older runtimes can still process newer scripts gracefully.

Listening for Errors

To respond to errors at runtime, bind to the OnError delegate on your UStoryFlowComponent.

C++ Example

C++
// In your actor's BeginPlay or initialization
UStoryFlowComponent* StoryFlow = FindComponentByClass<UStoryFlowComponent>();
if (StoryFlow)
{
    StoryFlow->OnError.AddDynamic(this, &AMyActor::HandleStoryFlowError);
}

// Handler function
void AMyActor::HandleStoryFlowError(const FString& ErrorMessage)
{
    UE_LOG(LogTemp, Warning, TEXT("StoryFlow error: %s"), *ErrorMessage);
    // Show error in your UI, log to analytics, etc.
}

Blueprint

In your actor's Blueprint, select the StoryFlowComponent and add an event binding for On Error in the Details panel under StoryFlow | Events. The event provides a single ErrorMessage string parameter.

Initialization Errors

These errors occur when calling StartDialogue() or StartDialogueWithScript() before the component is properly configured.

Error Message Cause Solution
No script configured for StoryFlowComponent Called StartDialogue() without setting the Script property. Set the Script property in the Details panel or use StartDialogueWithScript() instead.
StartDialogueWithScript called with empty ScriptPath Passed an empty string to StartDialogueWithScript(). Provide a valid script path (e.g., "Content/main.sfe").
StoryFlow Subsystem not available The UStoryFlowSubsystem hasn't initialized. This can happen if called too early in the game lifecycle. Ensure you call StartDialogue() after BeginPlay. The subsystem initializes with the game instance.
No StoryFlow project loaded No project asset exists at the default path and none was set manually. Import your StoryFlow project via the importer or call SetProject() on the subsystem.
Script not found: {path} The Script property references a script path that doesn't exist in the imported project. Check the script path matches one of the imported scripts. The Output Log lists all available scripts when this error occurs.
Start node (id=0) not found in script The script data doesn't contain a Start node with id "0". The script may be corrupted or was exported incorrectly. Re-export the project from StoryFlow Editor and re-import into Unreal. Verify the script has a Start node in the editor.

Graph Execution Errors

These errors occur during node graph traversal when the runtime encounters invalid connections or structural problems.

Error Message Cause Solution
Target node not found: {id} An edge references a node ID that doesn't exist in the script. The target node may have been deleted after the connection was created. Open the script in StoryFlow Editor and fix any broken connections. Re-export and re-import the project.
Max processing depth exceeded ({depth}) - possible cyclic graph The node processing loop has exceeded the safety limit. This happens when non-dialogue nodes form a cycle with no exit condition. Check for loops in your non-dialogue node chains. Make sure every loop has a Branch node that eventually exits the cycle.

Script & Flow Errors

These errors occur when using runScript or runFlow nodes to call other scripts or flows.

Error Message Cause Solution
RunScript node has no script path A runScript node has no script path configured. Open the script in StoryFlow Editor and set a valid script path on the Run Script node.
Start node not found in script: {path} The target script called by a runScript node is missing a Start node. Ensure the target script has a Start node. Re-export from StoryFlow Editor.
Max script nesting depth exceeded ({depth}) Scripts calling other scripts have exceeded the maximum nesting depth. This usually indicates a circular dependency. Check your Run Script nodes for circular references. Reorganize your script hierarchy to avoid loops.
RunFlow node has no flow ID A runFlow node has no flow selected. Open the script in StoryFlow Editor and configure the Run Flow node with a valid flow.
Too many nested flows - possible infinite loop Flows calling other flows have exceeded the maximum nesting depth. Check your Run Flow nodes for circular references. Make sure flows don't call themselves or form a loop.
EntryFlow not found for flowId: {id} A Run Flow node references a flow that doesn't exist in the script. Verify the flow exists in the script. The flow may have been renamed or deleted in the editor.

Depth Limits

Resource Maximum Depth Description
Script nesting 20 Maximum runScript calls deep before the runtime stops
Flow nesting 50 Maximum runFlow calls deep before the runtime stops

Forward Compatibility Warnings

When the StoryFlow Editor introduces a new node type that an older runtime version does not understand, the runtime emits a warning and continues execution gracefully. These messages are logged at Warning level through LogStoryFlow. They do not invoke the OnError delegate and they do not crash the game. The intent is to keep older plugin builds usable against newer exported projects while the user upgrades the plugin.

Warning Message Where It Fires Behavior
StoryFlow: Unsupported node type '{type}' at node {id}, skipping Flow dispatch. Emitted when the runtime encounters an unknown node type while walking the execution graph. The node is skipped. The runtime follows the outgoing edge if one exists and continues processing.
StoryFlow: Unsupported node type '{type}' at node {id}, returning default value Evaluator chains. Emitted when the evaluator is asked to resolve a value-producing node whose type is unknown. The evaluator returns the type's default value (false for bool, 0 for int, empty string, etc.). Deduplicated per-node-id-per-dialogue-run so a single chain only logs once.

If you see either warning in the Output Log, the most likely cause is that your StoryFlow Editor export uses a node introduced in a newer version of the project format than your installed plugin supports. Update the plugin to the matching version, or remove the unsupported node from the script in the StoryFlow Editor and re-export.

A concrete example: the map operation nodes (getMap, setMap, getMapValue, setMapValue, hasMapKey, mapSize, mapKeys, mapValues, removeMapKey, clearMap, forEachMap) and the modulo and moduloFloat math nodes require plugin 1.2.0 or later. On older plugins they surface as the "Unsupported node type" warnings above. The fix is updating the plugin. The StoryFlow Editor also flags this proactively: when a pre-1.2.0 plugin connects over Live Sync while the open project uses map variables, the editor shows a warning toast during the handshake telling you to update to 1.2.0+.

Deduplication Scope

The evaluator's "returning default value" warning is deduplicated per-node-id-per-dialogue-run. The first hit logs, subsequent hits on the same node during the same dialogue stay silent. This prevents log spam when an unsupported node sits inside a tight loop or is referenced repeatedly during evaluation. A fresh dialogue run resets the deduplication state.

Debugging Strategies

Filter the Output Log

All StoryFlow plugin messages use the LogStoryFlow log category. In the Output Log panel, type "StoryFlow" into the search box to filter out unrelated engine messages. This makes it much easier to see errors, warnings, and informational messages from the plugin.

Track Variable Changes

Bind to the OnVariableChanged delegate to monitor variable state during execution. This is especially useful for debugging Branch nodes that always take the same path - you can verify the boolean variable has the expected value at the moment the Branch node evaluates.

C++
StoryFlow->OnVariableChanged.AddDynamic(this, &AMyActor::OnVarChanged);

void AMyActor::OnVarChanged(const FStoryFlowVariable& Variable, bool bIsGlobal)
{
    UE_LOG(LogTemp, Log, TEXT("Variable '%s' (%s) changed to '%s' (global=%s)"),
        *Variable.Name, *Variable.Id, *Variable.Value.ToString(),
        bIsGlobal ? TEXT("true") : TEXT("false"));
}

Use Live Sync for Rapid Iteration

When debugging, use Live Sync to push changes from StoryFlow Editor to Unreal without restarting PIE. This lets you fix a broken connection in the editor and immediately test the fix in-game.

Cross-Reference with the Editor

Many plugin errors mirror editor runtime errors. If you see an error in Unreal, try playing the same script in StoryFlow Editor's Play Window to reproduce it. The editor's Runtime Debugger provides a visual, step-by-step view of execution that can pinpoint the exact node causing the problem.

Editor Errors Page

For a complete list of editor-side error messages and their solutions, see the Errors & Troubleshooting page in the editor documentation. Many errors are shared between the editor runtime and the Unreal plugin.

Common Issues

Dialogue Works in Editor but Not in Packaged Builds

Dialogue that runs correctly in PIE (Play In Editor) and Simulate mode but produces no output in a packaged build has two distinct causes. Match the symptoms before applying a fix - the remedies do not overlap.

Cause 1: the cooker did not include your StoryFlow assets. By default, the cooker only packages assets that are directly referenced by a map or Blueprint. Since StoryFlow assets are loaded at runtime by the subsystem, the cooker may skip them entirely. The symptom is the whole project going missing in the packaged build: no script resolves, and the runtime typically reports No StoryFlow project loaded because the project asset was cooked out along with everything else.

Fix: Tell the cooker to always include the StoryFlow content directory:

  1. Open Project Settings.
  2. Navigate to Platforms > Packaging (or search for "Additional Asset Directories to Cook").
  3. Under Additional Asset Directories to Cook, add /Game/StoryFlow.
  4. Package your project again.

Cause 2: a script or folder name that is invalid in an Unreal package name. Up to plugin version 1.2.1, a script's file name and each folder segment above it went into the package path untouched. Any name containing a character Unreal does not allow in package names - a space, an apostrophe, a dot - produced an asset the loader and cooker can never resolve. The editor and PIE keep working from the in-memory packages, so nothing looks wrong until the game is packaged.

Symptoms that point at this cause rather than at the cooker:

  • Only some dialogue is missing. Scripts whose names contain nothing but letters, digits, underscores or hyphens still work in the same packaged build.
  • The script's file name, or one of the folder names above it, contains a space, an apostrophe or a dot. That alone is enough. Nothing about the script's content matters.
  • On 1.2.2 and later, the sync log carries a warning naming the offending script and the path it imported as.
  • On 1.2.1 and earlier, the sync log carries Ensure condition failed: ConvertedToPath. A name containing a dot could also hard-crash the editor inside the asset registry during import.

Fix:

  1. Update the plugin to 1.2.2 or later. It sanitizes the script name and every folder segment above it, so the packages it creates are always resolvable.
  2. Delete the assets the broken sync produced - the Content/StoryFlow folder in a default setup. This step is not optional: 1.2.2 creates the correct assets but does not remove the old unusable ones.
  3. Sync again, or re-import the project.

Avoiding the Sanitized Name Entirely

Sanitizing keeps the asset resolvable but changes its name: an invalid segment is cleaned and given a short suffix so two distinct source names cannot collide after cleanup ("act 1" stays separate from "act_1"). If you would rather keep readable asset names, rename the script or folder in the StoryFlow Editor so every segment contains only letters, digits, underscores and hyphens. Either way the component's Script property is unaffected, because the project keys its script map on the raw relative path rather than the package path.

Sync Cannot Write an Asset

From v1.2.2, a .uasset that cannot be written is reported by name and skipped while the rest of the import continues, and its import hash is not recorded, so the next sync retries that asset instead of skipping it. On earlier versions a single unwritable file took the whole editor down. These messages are logged through LogStoryFlow and do not invoke the runtime's OnError delegate.

Message Cause Solution
Could not save '<file>': the file is not writable. The target .uasset is read-only on disk. Usually a file checked into revision control with no provider enabled in the editor, or one whose permissions were stripped. Clear the read-only flag, check the file out of source control or fix its permissions, then sync again. The message itself spells out all three.
Failed to save package '<name>' to '<file>'. The save failed for a reason other than a read-only target. Check file permissions on the content directory and free disk space, then sync again.
Could not save '<file>': checked out by <user>. The file is exclusively checked out by someone else, so the importer could not check it out before overwriting it. Resolve it in revision control - have the other user submit or release the file - then sync again. The rest of the import already completed.
'<file>' did not exist locally but revision control already tracks it, so your workspace is probably out of date. A teammate added that asset. Your local write landed without a checkout because there was nothing on disk to check out. Sync your workspace and resolve the file in revision control before submitting.
Saved '<file>' but could not mark it for add in revision control A newly created asset was written successfully, but the provider refused the mark-for-add. Add the file to your changelist by hand. The asset itself is on disk and usable.

No Provider, No Change

The revision control messages only appear when the Unreal Editor has a provider enabled. Without one, every checkout and mark-for-add call is a success no-op and sync behaves exactly as it did before v1.2.2. See Live Sync: Revision Control.

Need Help?

Join our Discord community to ask questions, share your projects, report bugs, and get support from the team and other users.

Join Discord