The documentation for hook_action_info() indicates the following about actions:

  1. The naming convention for an action function is MODULE_description-of-function_action.
  2. Actions that will be modifying object/entity properties should specify a behavior array containing changes_property.

However, it appears that trigger_assign_form_submit() expects that actions that change properties will have the name of the type of entity they affect as the first token of the action function name. For example, node_publish_action() causes the function to look for node_save_action(), while comment_publish_action() causes the function to look for comment_save_action().

This works fine for core modules, but breaks down for third-party modules. Consider a module I am writing called "comment_thread_actions", which provides additional actions for closing and opening discussion threads on nodes that have comments enabled. Because the actions my module exposes necessarily have to modify node properties, I indicate that my actions have the changes_property behavior. This leads core to believe that the appropriate save action for my triggers is comment_save_action() because it extracts the first token from the function name ("comment"), but the correct save action should be node_save_action().

The responsible code is around line 251 of trigger.admin.inc:

    if (strpos($form_state['values']['hook'], 'presave') === FALSE && isset($actions[$aid]['behavior']) && in_array('changes_property', $actions[$aid]['behavior'])) {
      // Determine the corresponding save action name for this action.
      $save_action = strtok($aid, '_') . '_save_action';  // Line 251
      // If no corresponding save action exists, we need to bail out.
      if (!isset($actions[$save_action])) {
        throw new Exception(t('Missing/undefined save action (%save_aid) for %aid action.', array('%save_aid' => $aid, '%aid' => $aid)));
      }

I am not sure the best way to solve this bug without allowing actions to indicate what save action function is appropriate.