Troubleshooting
Purpose
This page covers common issues, known limitations, and frequently asked questions about Reactive SO.
Common issues
Events not firing
Symptom: You call RaiseEvent() but nothing happens.
Diagnostic flowchart
graph TB
A["Events not firing"] --> B{"Event Channel<br/>assigned?"}
B -->|NO| C["Set asset<br/>in Inspector"]
B -->|YES| D{"Using<br/>?.RaiseEvent()?"}
D -->|NO| E["Add null-conditional<br/>operator"]
D -->|YES| F["Open Event Monitor"]
F --> G{"Event<br/>appearing?"}
G -->|NO| H["Publisher issue<br/>Check RaiseEvent call"]
G -->|YES| I{"Subscribers<br/>in #L column?"}
I -->|NO| J["No subscribers<br/>Check OnEnable"]
I -->|YES| K["Subscriber issue<br/>Check handler"]
Checklist
-
Check whether the event channel is assigned. Look for
Nonein the Inspector and drag the correct ScriptableObject asset. - Check whether you are using the null-conditional operator.
// Good eventChannel?.RaiseEvent(); // Bad - throws NullReferenceException if not assigned eventChannel.RaiseEvent(); -
Check whether anyone is subscribed. Open Event Monitor and check the #L column, use Subscribers List to see listeners, and verify the subscriber’s GameObject is active.
- Check whether the event is actually raising. Open Event Monitor. If the event appears, the problem is in subscribers. If the event does not appear, check the publisher code.
Memory leaks / duplicate events
Symptom: Events fire multiple times or memory grows after scene transitions.
Cause: Forgot to unsubscribe in OnDisable.
Fix
private void OnEnable()
{
eventChannel.OnEventRaised += HandleEvent;
}
private void OnDisable()
{
eventChannel.OnEventRaised -= HandleEvent; // Required!
}
Diagnosis: Use Subscribers List before and after scene transitions. If destroyed objects remain in the list, you have a leak.
Events fire too early
Symptom: Subscriber’s Start() has not run when the event fires.
Solutions
Option 1 - Delay the event
private IEnumerator Start()
{
yield return null; // Wait one frame
onGameStarted?.RaiseEvent();
}
Option 2 - Subscribe earlier
private void Awake()
{
eventChannel.OnEventRaised += HandleEvent;
}
private void OnDisable()
{
eventChannel.OnEventRaised -= HandleEvent;
}
Wrong event channel referenced
Symptom: Multiple event channels have similar names and you reference the wrong one.
Fix Use clear names and organize in folders:
ScriptableObjects/Events/
├── Player/
│ ├── OnPlayerDeath.asset
│ └── OnPlayerHealthChanged.asset
├── UI/
│ └── OnMenuOpened.asset
└── Game/
└── OnGamePaused.asset
Subscribers not updating
Symptom: Event fires but subscriber does not react.
Checklist
- Is the GameObject active?
- Is the MonoBehaviour enabled?
- Did
OnEnable()run? - Is the subscription correct?
// Correct eventChannel.OnEventRaised += HandleEvent; // Wrong - overwrites other subscribers eventChannel.OnEventRaised = HandleEvent; - Does the method signature match?
// For IntEventChannelSO void HandleEvent(int value) { } // Correct void HandleEvent() { } // Wrong signature
Known limitations
Caller information with UnityEvents
Caller information only works for direct code calls. It does not work when events are raised via UnityEvent (e.g., Button.OnClick in Inspector).
Works
public void OnButtonClick()
{
onButtonPressed?.RaiseEvent(); // Caller: "OnButtonClick"
}
Does not work
Inspector: Button.OnClick → EventChannel.RaiseEvent
Caller shows: "-"
Workaround: Create a wrapper method instead of calling RaiseEvent directly from Inspector.
Manual Trigger custom types
Manual Trigger only supports the 12 built-in event types. Custom types display a help message instead of a trigger button.
Subscribers List scope
Subscribers List only shows MonoBehaviour subscribers. Other subscribers (ScriptableObjects, static classes) appear in the #L count but not in the list.
Custom types with non-serializable fields
When using custom types with Variables or Event Channels, only serializable fields persist across scene transitions or domain reloads.
Unsupported types in custom structs/classes
| Type | Status |
|---|---|
Dictionary<K,V> | Not serialized |
Multidimensional arrays (int[,]) | Not serialized |
| Delegates / Events | Not serialized |
| Interfaces | Not serialized |
HashSet<T>, Queue<T>, Stack<T> | Not serialized |
Example of problematic custom type
[System.Serializable]
public struct GameProgress
{
public int level; // OK
public Dictionary<string, bool> achievements; // NOT serialized!
}
// VariableSO<GameProgress> will lose achievements data
Solution: Use serializable alternatives.
[System.Serializable]
public struct GameProgress
{
public int level;
public List<string> achievementKeys; // OK
public List<bool> achievementValues; // OK
}
ScriptableObject data loss on scene transition
Runtime data in ScriptableObjects may be lost if the SO is unloaded from memory. This can happen in the following cases.
- Editor: SO not selected in Inspector during scene transition
- Build: SO not referenced by any loaded scene
Affected components
- ReactiveEntitySetSO runtime data (entities)
- RuntimeSetSO items
- Custom non-serialized fields
Not affected
- VariableSO values (serialized by default)
- Event channel subscriptions are expected to re-subscribe in
OnEnable
Workaround: Ensure critical SOs are referenced by a persistent object (e.g., a DontDestroyOnLoad manager).
FAQ
Can I use Reactive SO in builds?
Yes. All features work in builds with zero overhead. Debugging tools (Event Monitor, Manual Trigger, Subscribers List, Caller Info) are Editor-only and automatically stripped from builds.
What is the performance cost?
Nearly zero. Event channels use standard C# events internally. Debugging features are completely removed from builds.
Can I use event channels with coroutines?
Yes.
private void OnEnable()
{
eventChannel.OnEventRaised += HandleEvent;
}
private void HandleEvent()
{
StartCoroutine(HandleEventCoroutine());
}
private IEnumerator HandleEventCoroutine()
{
// Your coroutine logic
}
Can I pass multiple values in one event?
Not directly. Use one of these approaches.
Option 1 - Use a struct
[System.Serializable]
public struct PlayerDeathData
{
public Vector3 position;
public string killerName;
public int score;
}
public class PlayerDeathEventChannelSO : EventChannelSO<PlayerDeathData> { }
Option 2 - Use multiple events
onPlayerDeath?.RaiseEvent();
onDeathPosition?.RaiseEvent(position);
onFinalScore?.RaiseEvent(score);
Can I subscribe from ScriptableObjects?
Yes.
public class GameSettings : ScriptableObject
{
[SerializeField] private VoidEventChannelSO onGameStarted;
private void OnEnable()
{
onGameStarted.OnEventRaised += HandleGameStarted;
}
private void OnDisable()
{
onGameStarted.OnEventRaised -= HandleGameStarted;
}
private void HandleGameStarted()
{
// Initialize settings
}
}
Note: ScriptableObject subscribers do not appear in Subscribers List but are counted in the #L column.
How do I unit test event channels?
using NUnit.Framework;
using Tang3cko.ReactiveSO;
public class EventChannelTests
{
[Test]
public void EventRaisesCorrectly()
{
// Arrange
var eventChannel = ScriptableObject.CreateInstance<IntEventChannelSO>();
int receivedValue = 0;
eventChannel.OnEventRaised += (value) => receivedValue = value;
// Act
eventChannel.RaiseEvent(42);
// Assert
Assert.AreEqual(42, receivedValue);
}
}
Can I use event channels for networking?
Event channels work locally within a single Unity instance. For networked games, consider the following approach.
- Use event channels for local game logic
- Use your networking solution for network communication
- Raise event channels in response to network events
Here is an example of raising local events from network callbacks.
[ClientRpc]
void RpcPlayerDeath()
{
// Runs on all clients
onPlayerDeath?.RaiseEvent(); // Local event for UI/audio
}
Still having issues?
If you are experiencing issues not covered here, try the following steps.
- Check Event Monitor to verify event flow
- Use Subscribers List to verify subscriptions
- Try Manual Trigger to isolate publisher vs subscriber issues
- Add
Debug.LoginOnEnable,OnDisable, and handlers - Review Getting Started for basic setup
Reporting issues
When reporting issues, include the following information.
- Unity version
- Reactive SO version
- Steps to reproduce
- Event Monitor output
- Subscribers List screenshot
For support, use the following channels.
References
- Event Channels Guide - Basic usage
- Debugging - Debugging tools
- Event Monitor - Real-time tracking