Skip to content

Reference Troubleshooting

github-actions[bot] edited this page Sep 11, 2026 · 10 revisions

Troubleshooting -- Common Issues & Solutions

Getting-Started | Reference-Faq | Getting-Started-Getting-Started | Reference-Glossary


Not receiving messages

Use the Editor tools to locate the failed stage before changing code:

  1. Enable Editor diagnostics and open Guides-Diagnostics#message-monitor. If the emission is absent, inspect the sender, route kind, and target/source context.
  2. Select the emission to inspect its exact message type and context. Enable stack-trace capture only when you need the emitting file and line.
  3. If the receiver uses a loaded-scene MessagingComponent, open Guides-Diagnostics#flow-graph. A missing component edge points to registration, token state, or provider setup. An existing edge with no calls points to context mismatch, an interceptor veto, or disabled state. Direct bus or token registrations outside those components do not appear in the graph; use bus logs and registration counters for those paths.
  4. Check the Guides-Inspector-Overlay for missing MessageAwareComponent base calls and provider warnings.

Then check the matching cause below:

  • Ensure your MessageRegistrationToken is enabled (Enable in OnEnable, Disable in OnDisable).
  • Verify the category matches the emission (Untargeted vs Targeted vs Broadcast).
  • Targeted/Broadcast require a valid InstanceId; ensure the target/source object exists when you emit.
  • In Unity, confirm your MessagingComponent exists on sender/receiver GameObjects.
  • CRITICAL: If inheriting from MessageAwareComponent, ensure your overrides call base methods:
    • base.RegisterMessageHandlers() - Call this FIRST in your override to preserve parent class registrations. Override RegisterForStringMessages => true separately when you want the built-in string demos.
    • base.Awake() - Call this if you override Awake(), or your token won't be created (this is the #1 cause of handlers not firing).
    • base.OnEnable() / base.OnDisable() - Call these so the token actually enables/disables.
    • base.OnDestroy() - Call this if you override OnDestroy(), or registrations leak past the component's lifetime and held references prevent GC.
    • Never use new to hide Unity methods (e.g., new void OnEnable()); always use override and call base.*.
    • For the complete table of guarded methods and the exact failure mode for each, see Getting-Started-Quick-Start#important-inheritance-and-base-calls in the quickstart.

Registration timing

  • ALWAYS register message handlers in Awake(), not Start().
  • MessageAwareComponent automatically calls RegisterMessageHandlers() in Awake().
  • Registering in Awake() ensures handlers are ready before other components' Start() methods run.
  • If you register in Start(), you may miss messages emitted by other components in their Start() methods.

Unexpected ordering

  • Check priority values on registrations; lower runs earlier. Same priority is registration order.
  • Interceptors always precede handlers and can cancel; confirm interceptors return true.

Double registration or over-deregistration warnings

  • Avoid calling stage/enable multiple times; pair registrations and lifecycles consistently.
  • Use Flow Graph to inspect loaded-scene MessagingComponent route topology. Review logs with bus.Log.Enabled = true for direct registrations or when you need the registration mutation history.

Allocations and boxing

  • Prefer struct messages implementing the generic interfaces: I*Message<T>.
  • Use readonly by-reference handler overloads to avoid copies.
  • Register handlers once in Awake/setup, not every frame: each registration allocates a small bounded amount, while ordinary typed steady-state struct dispatch is allocation-free. Struct global accept-all dispatch boxes the message, and emission-site stack-trace capture allocates while enabled. See the Reference-Faq#does-dxmessaging-allocate-memory-is-dispatch-zero-gc.

Emitting while disabled

  • If you need to emit when a component is disabled, use a bus not tied to enable state or set emitMessagesWhenDisabled on MessagingComponent.

Diagnostics overhead

  • Diagnostics are off by default. Leave them off in release builds (IMessageBus.GlobalDiagnosticsTargets = DiagnosticsTarget.Off); enable them only when inspecting message history. See Guides-Diagnostics.

Source generator did not generate Emit or handler methods

  • Mark the message type partial. The generator emits members into a second partial declaration, which requires the keyword on your type.
  • Apply a [DxUntargetedMessage], [DxTargetedMessage], or [DxBroadcastMessage] attribute, or implement the matching I*Message interface directly.
  • An assembly definition is not required -- generation runs for Unity's default Assembly-CSharp as well as for your own .asmdef assemblies.
  • After changing message types, let Unity finish recompiling; generated members appear once the analyzer reruns.

Memory grows in long sessions

  • Read bus.OccupiedTypeSlots and bus.OccupiedTargetSlots (or the global MessageHandler.MessageBus.OccupiedTypeSlots / OccupiedTargetSlots) at region boundaries to see whether per-type or per-target slots are the culprit.
  • Call MessageHandler.TrimAll(force: true) (or bus.Trim(force: true)) at scene unload or other natural transitions. Slots that survive a forced trim correspond to active registrations.
  • Tune the reclamation policy through DxMessagingRuntimeSettings. See the Guides-Memory-Reclamation for tuning recommendations and a leak-watching pattern.

Related Documentation

Clone this wiki locally