Investigate a journey enrollment
Use this when someone asks "why did Kari get this email", "why is Ola stuck", or "why did nobody from the webinar enter the journey".
Find the run
journeys_listto find the journey, thenjourneys_list_enrollmentswithcontactId(find the contact withcrm_search_contacts). Several rows mean several runs: the journey allows re-entry after a run ends.journeys_get_traceon the enrollment.
Read the trace
Every node visit is one step, in order. Each step has the node, the edge taken and a reason:
- branch steps say which rule matched (
rule 2 matched) orno rule matched. Rules are checked in order, so an early broad rule hides later ones. - split steps record the bucket (0–99) the person hashed into; the same person always lands in the same path.
- wait and wait_for steps with status
waitingare where the person is now.openWaitsshows when a timer fires or which event the run is waiting for and when it times out. - action steps show the result, or
failed: …with the error. A step with statusretryingwill try again; permanent errors (unknown contact, missing webhook) do not retry and follow the node'sonFail. - A step that throws an unexpected error (not an action's own failure) rolls back on its own, keeps the steps before it, and runs again after 1, 5, 15 and 60 minutes. The enrollment's
stepErrorscounts the attempts andlastErrorholds the message; after five in a row the run ends withstep_failedand the step shows statusfailed. Steps a run was in when it ended show statuscancelled. - The enrollment's
exitReasonsays how the run ended:reached_end,goal_reached,matched_exit,idle_timeout,loop_detected,wait_timeout,action_failed,step_failed,journey_archived,holdout,ejected, ornode_missing.idle_timeoutmeans the run made no progress forexit.idleDays— the deadline moves forward every time it advances.
context.trigger holds the event that started the run; context.lastEvent holds the last event a wait_for received.
Someone never entered
Check, in this order:
- The journey is
live(journeys_get). Draft and paused journeys enroll nobody. - The trigger: for an event trigger, the event name must match exactly (
analytics_list_product_event_names), and events older thanentry.lateEventWindowHoursare ignored. - The entry segment: the contact must match it and have a recorded lawful basis, must not be unsubscribed, and must not be marked do-not-contact.
- Re-entry: with
oncea person enters at most once; withonce_at_a_timenot while a run is open. - The holdout: an enrollment with
holdout: trueentered on purpose and was held back to measure lift.
Someone is stuck on a step
If the trace stops at a step that never started and the run is active with no next run time, the step is paused — by a person or by the monitor on a guardrail breach. journeys_get lists pausedNodes with the reason; journeys_get_guardrails shows the rates behind a monitor pause. Resuming the step releases everyone held there at once. Messages from that step that were already approved are held too, not failed: they stay approved and are checked again every 15 minutes, as they are while the whole journey is paused.
The trace is empty
Step traces of runs that ended are deleted after settings.traceRetentionDays (365 days unless the journey sets 30–3650). The run itself stays, with its exit reason and goal, so reports still count it; only the step-by-step log and the run's context are gone.
What to do
- A journey that behaves as designed but not as intended needs a new draft (
skill://journeys/build-journey); people already in it finish on their version. - To take one person out,
journeys_eject— but only when the operator asks you to.