instructure/canvas-lms · error · NoTransitionAllowed

There is no event # defined for the # state

Error message

There is no event #{name.to_sym} defined for the #{current_state} state

What it means

The workflow gem's process_event! raises NoTransitionAllowed when the requested event name is not defined on the object's current state. State machines have per-state event maps; calling an event that exists on other states but not this one is invalid.

Solutions

  1. Check the valid events for the current state before calling (current_state.events.key?(name)) or use the non-bang process_event which returns false instead of raising
  2. Reload the record to get the freshest state before transitioning
  3. Guard the UI to only render valid events for the record's state
  4. Rescue NoTransitionAllowed and handle the stale-transition case gracefully

Example fix

// before
record.process_event!(:publish)
// after
if record.current_state.events.key?(:publish)
  record.process_event!(:publish)
else
  Rails.logger.warn("publish not valid in #{record.current_state}")
end
Defensive patterns

Strategy: try-catch

Validate before calling

if obj.current_state.events.key?(event_name)
  obj.process_event!(event_name)
end

Try / catch

begin
  obj.process_event!(event_name)
rescue Workflow::NoTransitionAllowed
  Rails.logger.warn("#{event_name} invalid in #{obj.current_state}")
  obj.reload
end

Prevention

When it happens

Trigger: Calling obj.process_event!(:approve) when the current_state has no :approve event (e.g. approving an already-approved record); invoking events on records in terminal states; calling events in the wrong lifecycle order.

Common situations: Race conditions where two requests transition the same record and the second sees an updated state; stale UI data showing buttons for events no longer valid; missing state in a newly added workflow step.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/401079a29f2d91ac. Report an issue: GitHub.

Appendix: source

Thrown at gems/workflow/lib/workflow.rb:193

      @halted_because
    end

    # INSTRUCTURE:
    def process_event(name, *)
      success = true
      begin
        process_event!(name, *)
      rescue NoTransitionAllowed
        @halted = true
        @halted_because = $!
        success = false
      end
      success
    end

    def process_event!(name, *)
      event = current_state.events[name.to_sym]
      raise NoTransitionAllowed, "There is no event #{name.to_sym} defined for the #{current_state} state" if event.nil?

      @halted_because = nil
      @halted = false
      @raise_exception_on_halt = false
      return_value = run_action(event.action, *) || run_action_callback("do_#{event.name}", *)
      if @halted
        if @raise_exception_on_halt
          raise TransitionHalted, @halted_because
        else
          false
        end
      else
        run_on_transition(current_state, spec.states[event.transitions_to], name, *)
        transition(current_state, spec.states[event.transitions_to], name, *)
        return_value
      end
    end

View on GitHub (pinned to 1c9f0bb801)