There are two Wait step complaints, and they arrive in the same week. One client asks why a lead got the "see you tomorrow" reminder three hours before an appointment they booked that morning. Another asks why a contact has been sitting in the nurture for nine days when the sequence was supposed to send on day two.

Both look like GoHighLevel being flaky. Neither is. A contact that skips a wait and a contact that stalls in one are both following settings somebody chose, usually on the Wait action itself and occasionally on the workflow around it. The trouble is that those settings live in different panels, and the builder canvas shows you a box that says "Wait" and very little else.

This is the checklist I work through when a client reports either symptom. Everything about how the Wait action behaves comes from HighLevel's own help documentation, linked as we go. Where something is from our own operating experience rather than the docs, I say so.

First, name the wait you actually built

"Wait" in GoHighLevel is not one behavior. HighLevel's Wait action documentation lists a set of distinct types, and they fail in different ways:

  • A set period of time, in seconds, minutes, hours or days, fixed or pulled from a custom variable.
  • A specific date and time, with "on this date and time", "before this date" or "after this date".
  • A recurring schedule, weekly, monthly or yearly.
  • An upcoming appointment or booking, covering appointments and calendar events, service bookings and invoice due dates, at the scheduled time or a set duration before or after it.
  • The contact to reply, on a chosen channel, with an optional timeout.
  • The contact to take an action, such as clicking a trigger link or an email event, with an optional timeout.
  • Specific conditions to be met, built as segments joined by AND or OR, with an optional timeout.
  • A user to reply, meaning someone on the team, with an optional timeout.

The first four are clock waits. The last four are event waits. Clock waits are where skipping comes from. Event waits are where stalling comes from. Open the step and confirm which one it is before you theorize about anything else.

Why a contact skips the wait

The date had already passed

This is the reminder complaint, and it is the most common skip by a distance. For specific-date and appointment waits, HighLevel gives you a setting called If this date has already passed. The documented options are: continue to next action, go to a specific step, exit the contact from the automation, or skip all outbound communication actions until the next wait or event start date action. The FAQ on the same page is explicit that if the event or appointment time has already passed when the contact reaches the Wait step, the workflow uses the option you selected.

Now picture the standard reminder build: wait until 24 hours before the appointment, send the reminder. A lead books at 9am for 1pm the same day. When they reach the wait, "24 hours before" is already in the past. If the step is set to continue to next action, the reminder goes out immediately, and it says "tomorrow".

None of those four options is wrong in general. The point is that somebody has to pick one on purpose for every appointment wait, because a same-day booking is not an edge case for most service businesses. For a stacked reminder sequence, the skip-communications option is usually the honest choice: it bypasses the Email, SMS, Call and Voicemail actions until the next wait, so the contact falls through to the reminder that still makes sense.

A dynamic value that resolved to the past

Timed and date waits can read their value from a custom variable. HighLevel's documentation says dynamic values accept any custom variable that resolves to a valid date, time or number. When the field behind that variable holds a date that has already gone by, a stale renewal date or a follow-up date someone typed last year, you are back in the past-date case above. What happens when the variable is empty or not a valid date is not described in the article, so treat that as untested and fill the field before the contact reaches the step.

The condition was already true

A condition wait releases the contact, per the docs, as soon as any one segment evaluates as true, and segments are evaluated independently with no priority. Build a wait for "tag is customer OR opportunity is won" and add a contact who already carries that tag from an old import, and in our experience they move through without waiting at all. The wait did exactly its job. It was just asked a question whose answer was already yes.

The timeout was shorter than you remember

Every event wait has an optional timeout, and when it fires the contact moves forward whether or not the event happened. A one-hour timeout on a "contact replies" wait that someone set while testing is a skip that looks random from the outside. Read the duration, do not assume it.

Why a contact stalls in the wait

The event never happened and there is no timeout

This is the mirror image. Reply waits, contact action waits, condition waits and user reply waits all treat the timeout as optional. If it is off, the step is waiting for the contact to reply, click or meet a condition, and nothing in the step moves them on time alone. A contact who never replies to the day-one text is not stuck because of a bug. They are waiting, exactly as instructed, for something that is not coming.

One related trap: HighLevel notes that a Send Email or SMS action needs to be present before a contact reply wait, so a reply wait placed ahead of any send has nothing to listen to.

The Advance Window held them

Timed waits have an optional Advance Window with three filters: Resume On specific weekdays, Resume Between Hours, and an additional date filter. It also means a wait that "should" have finished on Saturday will not release the contact until whatever day and hour the window allows. The help article does not spell out exactly how a contact who reaches the step outside the window is scheduled, so if timing matters to the minute, test it on a contact you control.

The workflow's Time Window paused the send

This one presents as a stalled wait when the wait itself finished on schedule. HighLevel's workflow settings overview describes the Time Window as restricting when communication actions like SMS and email can execute. If an action is scheduled to run outside the window, it is paused and resumes at the next available time slot. Internal actions such as adding a tag or updating a field are not affected. So the tag after the wait gets applied on time, the SMS after the wait does not, and the contact looks frozen between the two.

The timezone was not the one you were thinking in

The same settings page explains that the workflow timezone governs every time-dependent step. It can be the account timezone or the contact's timezone, and when a contact has no timezone the account timezone is used. A "wait until 9am" that you checked against your own clock can release hours away from what you expected for a client in another state, or for a contact whose timezone was imported wrong.

You edited the wait, and they kept the old one

HighLevel states plainly that editing the Wait action does not update the wait for contacts already in that step. Shorten a seven-day wait to two days and everyone already in it still waits seven. Changes to the steps after the wait can apply as those contacts continue, including edits to existing actions and newly added actions. So the fix you shipped is real for new contacts and invisible for the ones the client is complaining about.

When the contact did not stall, they left

Some "stuck in the wait" reports are contacts who are not in the workflow at all anymore. Three ways that happens without anyone noticing:

  • Stop on Response. Per the workflow settings documentation, the workflow ends for a contact who responds to a message sent from that workflow. A contact who texted "ok" to the first message will never see the third.
  • Another workflow removed them. HighLevel's improved execution logs article lists an exit status of Removed by External Workflow Action, meaning an action in a different workflow took them out.
  • A snapshot refresh deleted the step. The same article notes that contacts waiting on a deleted step may be removed automatically so they do not get stuck, and the log shows "Removed by - Snapshot Refresh". If you push snapshot updates into client accounts, this is worth knowing before you restructure a live sequence. We wrote more about that risk in why GoHighLevel snapshots break.

Prove it from the logs before you change anything

Guessing at wait behavior wastes an afternoon. The workflow's Enrollment History and Execution Logs answer the question directly. The execution logs highlight actions that hit an error, and the enrollment history shows why a contact exited, with statuses including Workflow Completed, Removed by Workflow Action and Removed by External Workflow Action.

The most useful tool for this specific problem is Highlight Contact Path. Opened from the enrollment or execution history, it draws that contact's route on the builder canvas and marks the nodes they bypassed, the nodes that errored, and where they entered and exited. A skipped wait shows up as a bypassed node. A stalled contact shows up as still in progress at the wait.

If the path shows the contact moving on but a later action failing quietly, the wait was never the problem. Look at what the next actions reference, because a dead pipeline stage or user ID behind the wait fails without an error, which we covered in how invalid IDs kill GHL automations.

Build rules that prevent both

  • Set past-date handling deliberately on every appointment and date wait. Never leave it on whatever it defaulted to. For reminder ladders, prefer skipping communications so contacts fall through to the next reminder that still makes sense.
  • Give every event wait a timeout and a path for the timeout. If no reply should mean a different message, build that branch. Our post on if/else branching in GHL workflows covers when a branch earns its place.
  • Check condition waits against contacts who are already true. If an existing tag or field would release them on arrival, add a filter at the trigger, not a hope at the wait.
  • When you change a wait, plan for the contacts already in it. The edit does not reach them.

Doing this across a portfolio

On one workflow, all of this is a ten-minute read. The problem is that every one of these settings sits inside a step's configuration panel, and nobody opens forty wait steps across fifteen sub-accounts to check the past-date option. So one reminder bug ships into every client that gets the sequence.

GHL Command is how I read this at scale on my own accounts. It reads each workflow's full action list, not just its name and status, so I can ask Claude to pull every wait step across every sub-account I manage and show which ones have no timeout or no deliberate past-date handling. It runs from Claude on my own machine, and the client credentials stay on my computer. That is the same reason we argue for running the portfolio from one place instead of one account at a time.

Flat $97/mo, every sub-account you manage included, never billed per account.

Find the wait steps that will skip or stall before a client does. Flat $97/mo.

Read every workflow's real action list across every GoHighLevel sub-account you manage, and spot the missing timeouts and unhandled past dates from one place.

See how it works

Frequently asked questions

Why did an appointment reminder skip the wait and send immediately?
Usually because the appointment was booked inside the reminder window. For appointment and date waits, HighLevel applies your If this date has already passed choice when the time has already gone by. If that choice is continue to next action, the reminder sends at once.

Why is a contact stuck in a Wait step for days?
Check whether it is an event wait with no timeout, which waits indefinitely for a reply, click or condition. Then check the step's Advance Window and the workflow's Time Window, which can hold a release or a send until an allowed day and hour.

If I edit a Wait step, do contacts already in it get the new timing?
No. HighLevel documents that editing the Wait action does not update the wait for contacts already in that step. Later steps you edit or add can apply to them when they continue.