diff --git a/src/applications/herald/adapter/HeraldAdapter.php b/src/applications/herald/adapter/HeraldAdapter.php
--- a/src/applications/herald/adapter/HeraldAdapter.php
+++ b/src/applications/herald/adapter/HeraldAdapter.php
@@ -1203,7 +1203,15 @@
     $rule_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
 
     $action_type = $action->getAction();
-    $action_name = idx($this->getActionNameMap($rule_global), $action_type);
+
+    $default = $this->isHeraldCustomKey($action_type)
+      ? pht('(Unknown Custom Action "%s") equals', $action_type)
+      : pht('(Unknown Action "%s") equals', $action_type);
+
+    $action_name = idx(
+      $this->getActionNameMap($rule_global),
+      $action_type,
+      $default);
 
     $target = $this->renderActionTargetAsText($action, $handles);
 
@@ -1525,7 +1533,9 @@
     $supported = $this->getActions($rule_type);
     $supported = array_fuse($supported);
     if (empty($supported[$action])) {
-      throw new Exception(
+      return new HeraldApplyTranscript(
+        $effect,
+        false,
         pht(
           'Adapter "%s" does not support action "%s" for rule type "%s".',
           get_class($this),
@@ -1548,7 +1558,9 @@
     $result = $this->handleCustomHeraldEffect($effect);
 
     if (!$result) {
-      throw new Exception(
+      return new HeraldApplyTranscript(
+        $effect,
+        false,
         pht(
           'No custom action exists to handle rule action "%s".',
           $action));
diff --git a/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php b/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php
--- a/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php
+++ b/src/applications/herald/adapter/HeraldDifferentialDiffAdapter.php
@@ -154,7 +154,10 @@
             pht('Blocked diff.'));
           break;
         default:
-          throw new Exception(pht('No rules to handle action "%s"!', $action));
+          $result[] = new HeraldApplyTranscript(
+            $effect,
+            false,
+            pht('No rules to handle action "%s"!', $action));
       }
     }
 
diff --git a/src/applications/herald/controller/HeraldRuleController.php b/src/applications/herald/controller/HeraldRuleController.php
--- a/src/applications/herald/controller/HeraldRuleController.php
+++ b/src/applications/herald/controller/HeraldRuleController.php
@@ -320,7 +320,7 @@
       try {
         $adapter->willSaveAction($rule, $obj);
       } catch (HeraldInvalidActionException $ex) {
-        $errors[] = $ex;
+        $errors[] = $ex->getMessage();
       }
 
       $actions[] = $obj;
@@ -354,7 +354,6 @@
     if ($rule->getConditions()) {
       $serial_conditions = array();
       foreach ($rule->getConditions() as $condition) {
-
         $value = $condition->getValue();
         switch ($condition->getFieldName()) {
           case HeraldAdapter::FIELD_TASK_PRIORITY:
@@ -394,10 +393,10 @@
     $serial_actions = array(
       array('default', ''),
     );
+
     if ($rule->getActions()) {
       $serial_actions = array();
       foreach ($rule->getActions() as $action) {
-
         switch ($action->getAction()) {
           case HeraldAdapter::ACTION_FLAG:
           case HeraldAdapter::ACTION_BLOCK:
@@ -438,21 +437,39 @@
     // names of, so that saving a rule without touching anything doesn't change
     // it.
     foreach ($rule->getConditions() as $condition) {
-      if (empty($field_map[$condition->getFieldName()])) {
-        $field_map[$condition->getFieldName()] = pht('<Unknown Field>');
+      $field_name = $condition->getFieldName();
+
+      if (empty($field_map[$field_name])) {
+        $field_map[$field_name] = pht('<Unknown Field "%s">', $field_name);
       }
     }
 
     $actions = $adapter->getActions($rule->getRuleType());
     $action_map = array_select_keys($all_actions, $actions);
 
+    // Populate any actions which exist in the rule but which we don't know the
+    // names of, so that saving a rule without touching anything doesn't change
+    // it.
+    foreach ($rule->getActions() as $action) {
+      $action_name = $action->getAction();
+
+      if (empty($action_map[$action_name])) {
+        $action_map[$action_name] = pht('<Unknown Action "%s">', $action_name);
+      }
+    }
+
+
     $config_info = array();
     $config_info['fields'] = $field_map;
     $config_info['conditions'] = $all_conditions;
     $config_info['actions'] = $action_map;
 
     foreach ($config_info['fields'] as $field => $name) {
-      $field_conditions = $adapter->getConditionsForField($field);
+      try {
+        $field_conditions = $adapter->getConditionsForField($field);
+      } catch (Exception $ex) {
+        $field_conditions = array(HeraldAdapter::CONDITION_UNCONDITIONALLY);
+      }
       $config_info['conditionMap'][$field] = $field_conditions;
     }
 
@@ -468,9 +485,15 @@
     $config_info['rule_type'] = $rule->getRuleType();
 
     foreach ($config_info['actions'] as $action => $name) {
-      $config_info['targets'][$action] = $adapter->getValueTypeForAction(
-        $action,
-       $rule->getRuleType());
+      try {
+        $action_value = $adapter->getValueTypeForAction(
+          $action,
+         $rule->getRuleType());
+      } catch (Exception $ex) {
+        $action_value = array(HeraldAdapter::VALUE_NONE);
+      }
+
+      $config_info['targets'][$action] = $action_value;
     }
 
     $changeflag_options =
diff --git a/src/applications/herald/controller/HeraldTranscriptController.php b/src/applications/herald/controller/HeraldTranscriptController.php
--- a/src/applications/herald/controller/HeraldTranscriptController.php
+++ b/src/applications/herald/controller/HeraldTranscriptController.php
@@ -380,7 +380,10 @@
         $item->setState(PHUIObjectItemView::STATE_FAIL);
       }
 
-      $rule = idx($action_names, $apply_xscript->getAction(), pht('Unknown'));
+      $rule = idx(
+        $action_names,
+        $apply_xscript->getAction(),
+        pht('Unknown Action "%s"', $apply_xscript->getAction()));
 
       $item->setHeader(pht('%s: %s', $rule, $target));
       $item->addAttribute($apply_xscript->getReason());
diff --git a/src/applications/herald/engine/HeraldEngine.php b/src/applications/herald/engine/HeraldEngine.php
--- a/src/applications/herald/engine/HeraldEngine.php
+++ b/src/applications/herald/engine/HeraldEngine.php
@@ -272,6 +272,17 @@
       $result = false;
     } else {
       foreach ($conditions as $condition) {
+
+        try {
+          $object->getHeraldField($condition->getFieldName());
+        } catch (Exception $ex) {
+          $reason = pht(
+            'Field "%s" does not exist!',
+            $condition->getFieldName());
+          $result = false;
+          break;
+        }
+
         $match = $this->doesConditionMatch($rule, $condition, $object);
 
         if (!$all && $match) {
diff --git a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js
--- a/webroot/rsrc/js/application/herald/HeraldRuleEditor.js
+++ b/webroot/rsrc/js/application/herald/HeraldRuleEditor.js
@@ -254,6 +254,11 @@
 
     _renderValueInputForRow : function(row_id) {
       var cond = this._config.conditions[row_id];
+
+      if (!cond[1]) {
+        return;
+      }
+
       var type = this._config.info.values[cond[0]][cond[1]];
 
       var input = this._buildInput(type);