Expose an actions provider on RuleConfiguredTarget instances.

Given a target (for example from a skylark aspect), one will be able to access a list of actions that the target generated using "target.actions". This is without additional memory footprint.

Actions themselves are not fully exposed to skylark (and thus there isn't much meaning to gather from them in skylark yet). Access methods will follow soon.

RELNOTES: None.
PiperOrigin-RevId: 188098079
diff --git a/src/main/java/com/google/devtools/build/lib/actions/ActionLookupValue.java b/src/main/java/com/google/devtools/build/lib/actions/ActionLookupValue.java
index bbc3493..f02185b 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/ActionLookupValue.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/ActionLookupValue.java
@@ -13,16 +13,11 @@
 // limitations under the License.
 package com.google.devtools.build.lib.actions;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.MoreObjects;
-import com.google.common.base.MoreObjects.ToStringHelper;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.SkyValue;
 import java.util.ArrayList;
@@ -31,34 +26,37 @@
 import javax.annotation.Nullable;
 
 /**
- * Base class for all values which can provide the generating action of an artifact. The primary
- * instance of such lookup values is {@code ConfiguredTargetValue}. Values that hold the generating
- * actions of target completion values and build info artifacts also fall into this category.
+ * Base class for all values which can provide the generating action of an artifact.
  */
-public class ActionLookupValue implements SkyValue {
-  protected final List<ActionAnalysisMetadata> actions;
-  @VisibleForSerialization protected final ImmutableMap<Artifact, Integer> generatingActionIndex;
+public abstract class ActionLookupValue implements SkyValue {
 
-  protected ActionLookupValue(
-      ActionAnalysisMetadata action,
-      boolean removeActionAfterEvaluation) {
-    this(Actions.GeneratingActions.fromSingleAction(action), removeActionAfterEvaluation);
+  private final boolean removeActionsAfterEvaluation;
+
+  public ActionLookupValue(boolean removeActionsAfterEvaluation) {
+    this.removeActionsAfterEvaluation = removeActionsAfterEvaluation;
   }
 
-  @VisibleForTesting
-  public ActionLookupValue(
-      Actions.GeneratingActions generatingActions, boolean removeActionsAfterEvaluation) {
-    this(
-        removeActionsAfterEvaluation
-            ? new ArrayList<>(generatingActions.getActions())
-            : ImmutableList.copyOf(generatingActions.getActions()),
-        generatingActions.getGeneratingActionIndex());
-  }
+  /**
+   * Returns a list of actions registered by this {@link SkyValue}.
+   */
+  protected abstract ArrayList<ActionAnalysisMetadata> getActions();
 
-  protected ActionLookupValue(
-      List<ActionAnalysisMetadata> actions, ImmutableMap<Artifact, Integer> generatingActionIndex) {
-    this.actions = actions;
-    this.generatingActionIndex = generatingActionIndex;
+  /**
+   * Returns a map where keys are artifacts generated by this {@link SkyValue}, and values are
+   * the index of the action which generates this artifact.
+   */
+  protected abstract ImmutableMap<Artifact, Integer> getGeneratingActionIndex();
+
+  /**
+   * Returns the index of the action that generates {@code artifact} in this value, or null if this
+   * value does not have a generating action for this artifact. The index together with the key for
+   * this {@link ActionLookupValue} uniquely identifies the action.
+   *
+   * <p>Unlike {@link #getAction}, this may be called after action execution.
+   */
+  @Nullable
+  public Integer getGeneratingActionIndex(Artifact artifact) {
+    return getGeneratingActionIndex().get(artifact);
   }
 
   /**
@@ -73,19 +71,7 @@
     if (actionIndex == null) {
       return null;
     }
-    return getActionAnalysisMetadata(actionIndex);
-  }
-
-  /**
-   * Returns the index of the action that generates {@code artifact} in this value, or null if this
-   * value does not have a generating action for this artifact. The index together with the key for
-   * this {@link ActionLookupValue} uniquely identifies the action.
-   *
-   * <p>Unlike {@link #getAction}, this may be called after action execution.
-   */
-  @Nullable
-  public Integer getGeneratingActionIndex(Artifact artifact) {
-    return generatingActionIndex.get(artifact);
+    return getActions().get(actionIndex);
   }
 
   /**
@@ -95,17 +81,13 @@
    */
   @SuppressWarnings("unchecked") // We test to make sure it's an Action.
   public Action getAction(int index) {
-    ActionAnalysisMetadata result = getActionAnalysisMetadata(index);
+    ActionAnalysisMetadata result = getActions().get(index);
     Preconditions.checkState(result instanceof Action, "Not action: %s %s %s", result, index, this);
     return (Action) result;
   }
 
-  private ActionAnalysisMetadata getActionAnalysisMetadata(int index) {
-    return Preconditions.checkNotNull(actions.get(index), "null action: %s %s", index, this);
-  }
-
   public ActionTemplate<?> getActionTemplate(int index) {
-    ActionAnalysisMetadata result = getActionAnalysisMetadata(index);
+    ActionAnalysisMetadata result = getActions().get(index);
     Preconditions.checkState(
         result instanceof ActionTemplate, "Not action template: %s %s %s", result, index, this);
     return (ActionTemplate<?>) result;
@@ -116,27 +98,12 @@
    * take the proper action.
    */
   public boolean isActionTemplate(int index) {
-    return actions.get(index) instanceof ActionTemplate;
+    return getActions().get(index) instanceof ActionTemplate;
   }
 
   /** To be used only when checking consistency of the action graph -- not by other values. */
   public Map<Artifact, ActionAnalysisMetadata> getMapForConsistencyCheck() {
-    return getMapForConsistencyCheck(generatingActionIndex, actions);
-  }
-
-  protected ToStringHelper getStringHelper() {
-    return MoreObjects.toStringHelper(this)
-        .add("actions", actions)
-        .add("generatingActionIndex", generatingActionIndex);
-  }
-
-  @Override
-  public String toString() {
-    return getStringHelper().toString();
-  }
-
-  public int getNumActions() {
-    return actions.size();
+    return getMapForConsistencyCheck(getGeneratingActionIndex(), getActions());
   }
 
   public static Map<Artifact, ActionAnalysisMetadata> getMapForConsistencyCheck(
@@ -146,6 +113,13 @@
   }
 
   /**
+   * Returns the number of {@link Action} objects present in this value.
+   */
+  public int getNumActions() {
+    return getActions().size();
+  }
+
+  /**
    * If this object was initialized with {@code removeActionsAfterEvaluation} and {@link
    * Action#canRemoveAfterExecution()} is true for {@code action}, then remove this action from this
    * object's index as a memory-saving measure. The {@code artifact -> index} mapping remains
@@ -153,21 +127,18 @@
    */
   @ThreadSafe
   public void actionEvaluated(int actionIndex, Action action) {
-    if (!action.canRemoveAfterExecution()) {
-      return;
-    }
-    if (actions instanceof ArrayList) {
+    if (removeActionsAfterEvaluation && action.canRemoveAfterExecution()) {
       // This method may concurrently mutate an ArrayList, which is unsafe on its face. However,
       // ArrayList mutation on different indices that does not affect the size of the ArrayList is
       // safe, and that is what does this code does.
-      ArrayList<ActionAnalysisMetadata> actionArrayList =
-          (ArrayList<ActionAnalysisMetadata>) actions;
+      ArrayList<ActionAnalysisMetadata> actionArrayList = getActions();
       ActionAnalysisMetadata oldAction = actionArrayList.set(actionIndex, null);
       Preconditions.checkState(
           action.equals(oldAction), "Not same: %s %s %s %s", action, oldAction, this, actionIndex);
     }
   }
 
+
   /**
    * All subclasses of ActionLookupValue "own" artifacts with {@link ArtifactOwner}s that are
    * subclasses of ActionLookupKey. This allows callers to easily find the value key, while
diff --git a/src/main/java/com/google/devtools/build/lib/actions/BasicActionLookupValue.java b/src/main/java/com/google/devtools/build/lib/actions/BasicActionLookupValue.java
new file mode 100644
index 0000000..7ac35c7
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/actions/BasicActionLookupValue.java
@@ -0,0 +1,69 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.actions;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.MoreObjects.ToStringHelper;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
+import java.util.ArrayList;
+
+/**
+ * Basic implementation of {@link ActionLookupValue} where the value itself owns and maintains
+ * the list of generating actions.
+ */
+public class BasicActionLookupValue extends ActionLookupValue {
+  protected final ArrayList<ActionAnalysisMetadata> actions;
+  @VisibleForSerialization protected final ImmutableMap<Artifact, Integer> generatingActionIndex;
+
+  protected BasicActionLookupValue(
+      ActionAnalysisMetadata action,
+      boolean removeActionAfterEvaluation) {
+    this(Actions.GeneratingActions.fromSingleAction(action), removeActionAfterEvaluation);
+  }
+
+  protected BasicActionLookupValue(
+      ArrayList<ActionAnalysisMetadata> actions,
+      ImmutableMap<Artifact, Integer> generatingActionIndex,
+      boolean removeActionsAfterEvaluation) {
+    super(removeActionsAfterEvaluation);
+    this.actions = actions;
+    this.generatingActionIndex = generatingActionIndex;
+  }
+
+  @VisibleForTesting
+  public BasicActionLookupValue(
+      Actions.GeneratingActions generatingActions, boolean removeActionsAfterEvaluation) {
+    this(new ArrayList<>(generatingActions.getActions()),
+        generatingActions.getGeneratingActionIndex(),
+        removeActionsAfterEvaluation);
+  }
+
+  @Override
+  protected ArrayList<ActionAnalysisMetadata> getActions() {
+    return actions;
+  }
+
+  @Override
+  protected ImmutableMap<Artifact, Integer> getGeneratingActionIndex() {
+    return generatingActionIndex;
+  }
+
+  protected ToStringHelper getStringHelper() {
+    return MoreObjects.toStringHelper(this)
+        .add("actions", actions)
+        .add("generatingActionIndex", generatingActionIndex);
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
index fa68906..f963a22 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ConfiguredTargetFactory.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.lib.actions.ArtifactOwner;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
 import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
 import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
@@ -233,7 +234,7 @@
       OrderedSetMultimap<Attribute, ConfiguredTargetAndTarget> prerequisiteMap,
       ImmutableMap<Label, ConfigMatchingProvider> configConditions,
       @Nullable ToolchainContext toolchainContext)
-      throws InterruptedException {
+      throws InterruptedException, ActionConflictException {
     if (target instanceof Rule) {
       try {
         CurrentRuleTracker.beginConfiguredTarget(((Rule) target).getRuleClassObject());
@@ -307,7 +308,7 @@
       OrderedSetMultimap<Attribute, ConfiguredTargetAndTarget> prerequisiteMap,
       ImmutableMap<Label, ConfigMatchingProvider> configConditions,
       @Nullable ToolchainContext toolchainContext)
-      throws InterruptedException {
+      throws InterruptedException, ActionConflictException {
 
     // Load the requested toolchains into the ToolchainContext.
     if (toolchainContext != null) {
@@ -339,36 +340,39 @@
 
     MissingFragmentPolicy missingFragmentPolicy =
         configurationFragmentPolicy.getMissingFragmentPolicy();
-    if (missingFragmentPolicy != MissingFragmentPolicy.IGNORE
-        && !configuration.hasAllFragments(
-            configurationFragmentPolicy.getRequiredConfigurationFragments())) {
-      if (missingFragmentPolicy == MissingFragmentPolicy.FAIL_ANALYSIS) {
-        ruleContext.ruleError(missingFragmentError(ruleContext, configurationFragmentPolicy));
-        return null;
-      }
-      // Otherwise missingFragmentPolicy == MissingFragmentPolicy.CREATE_FAIL_ACTIONS:
-      return createFailConfiguredTarget(ruleContext);
-    }
 
-    if (rule.getRuleClassObject().isSkylark()) {
-      // TODO(bazel-team): maybe merge with RuleConfiguredTargetBuilder?
-      return SkylarkRuleConfiguredTargetUtil.buildRule(
-          ruleContext,
-          rule.getRuleClassObject().getConfiguredTargetFunction(),
-          env.getSkylarkSemantics());
-    } else {
-      RuleClass.ConfiguredTargetFactory<ConfiguredTarget, RuleContext> factory =
-          rule.getRuleClassObject().<ConfiguredTarget, RuleContext>getConfiguredTargetFactory();
-      Preconditions.checkNotNull(factory, rule.getRuleClassObject());
-      try {
-        return factory.create(ruleContext);
-      } catch (RuleErrorException ruleErrorException) {
-        // Returning null in this method is an indication an error occurred. Exceptions are not
-        // propagated, as this would show a nasty stack trace to users, and only provide info
-        // on one specific failure with poor messaging. By returning null, the caller can
-        // inspect ruleContext for multiple errors and output thorough messaging on each.
-        return null;
+    try {
+      if (missingFragmentPolicy != MissingFragmentPolicy.IGNORE
+          && !configuration.hasAllFragments(
+              configurationFragmentPolicy.getRequiredConfigurationFragments())) {
+        if (missingFragmentPolicy == MissingFragmentPolicy.FAIL_ANALYSIS) {
+          ruleContext.ruleError(missingFragmentError(ruleContext, configurationFragmentPolicy));
+          return null;
+        }
+        // Otherwise missingFragmentPolicy == MissingFragmentPolicy.CREATE_FAIL_ACTIONS:
+        return createFailConfiguredTarget(ruleContext);
       }
+      if (rule.getRuleClassObject().isSkylark()) {
+        // TODO(bazel-team): maybe merge with RuleConfiguredTargetBuilder?
+        return SkylarkRuleConfiguredTargetUtil.buildRule(
+            ruleContext,
+            rule.getRuleClassObject().getConfiguredTargetFunction(),
+            env.getSkylarkSemantics());
+      } else {
+        RuleClass.ConfiguredTargetFactory<ConfiguredTarget, RuleContext, ActionConflictException>
+            factory =
+                rule.getRuleClassObject()
+                    .<ConfiguredTarget, RuleContext, ActionConflictException>
+                        getConfiguredTargetFactory();
+        Preconditions.checkNotNull(factory, rule.getRuleClassObject());
+        return factory.create(ruleContext);
+      }
+    } catch (RuleErrorException ruleErrorException) {
+      // Returning null in this method is an indication a rule error occurred. Exceptions are not
+      // propagated, as this would show a nasty stack trace to users, and only provide info
+      // on one specific failure with poor messaging. By returning null, the caller can
+      // inspect ruleContext for multiple errors and output thorough messaging on each.
+      return null;
     }
   }
 
@@ -525,7 +529,8 @@
    * A pseudo-implementation for configured targets that creates fail actions for all declared
    * outputs, both implicit and explicit.
    */
-  private static ConfiguredTarget createFailConfiguredTarget(RuleContext ruleContext) {
+  private static ConfiguredTarget createFailConfiguredTarget(RuleContext ruleContext)
+      throws RuleErrorException, ActionConflictException {
     RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext);
     if (!ruleContext.getOutputArtifacts().isEmpty()) {
       ruleContext.registerAction(new FailAction(ruleContext.getActionOwner(),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
index 954f512..e40d8d3 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetBuilder.java
@@ -20,7 +20,10 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.Actions;
+import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.analysis.constraints.ConstraintSemantics;
 import com.google.devtools.build.lib.analysis.constraints.EnvironmentCollection;
@@ -40,6 +43,7 @@
 import com.google.devtools.build.lib.packages.Info;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.packages.Provider;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.TargetUtils;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Type;
@@ -76,10 +80,8 @@
     add(VisibilityProvider.class, new VisibilityProviderImpl(ruleContext.getVisibility()));
   }
 
-  /**
-   * Constructs the RuleConfiguredTarget instance based on the values set for this Builder.
-   */
-  public ConfiguredTarget build() {
+  /** Constructs the RuleConfiguredTarget instance based on the values set for this Builder. */
+  public ConfiguredTarget build() throws RuleErrorException, ActionConflictException {
     if (ruleContext.getConfiguration().enforceConstraints()) {
       checkConstraints();
     }
@@ -140,8 +142,15 @@
     }
 
     TransitiveInfoProviderMap providers = providersBuilder.build();
-
-    return new RuleConfiguredTarget(ruleContext, providers);
+    AnalysisEnvironment analysisEnvironment = ruleContext.getAnalysisEnvironment();
+    GeneratingActions generatingActions =
+        Actions.filterSharedActionsAndThrowActionConflict(
+            analysisEnvironment.getActionKeyContext(), analysisEnvironment.getRegisteredActions());
+    return new RuleConfiguredTarget(
+        ruleContext,
+        providers,
+        generatingActions.getActions(),
+        generatingActions.getGeneratingActionIndex());
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetFactory.java
index 30b1ef3..ba6272d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleConfiguredTargetFactory.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.analysis;
 
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.packages.RuleClass;
 
 /**
@@ -21,100 +22,103 @@
  *
  * <p>Here follows an overview of how loading and analysis works in Bazel:
  *
- * <p>Actions (i.e. commands that are run during the build) are created by configured targets
- * (see {@link ConfiguredTarget}), which are a pair of a target (e.g. <code>//src:bazel</code>) and
- * a {@link com.google.devtools.build.lib.analysis.config.BuildConfiguration}, which is a blob of
- * data that contains extra information about how the target should be built (for example, for which
+ * <p>Actions (i.e. commands that are run during the build) are created by configured targets (see
+ * {@link ConfiguredTarget}), which are a pair of a target (e.g. <code>//src:bazel</code>) and a
+ * {@link com.google.devtools.build.lib.analysis.config.BuildConfiguration}, which is a blob of data
+ * that contains extra information about how the target should be built (for example, for which
  * platform or with which C++ preprocessor definitions). Accordingly, a target can give rise to
  * multiple configured targets, for example, if it needs to be built both for the host and the
  * target configuration.
  *
  * <p>The process of creating the appropriate {@link com.google.devtools.build.lib.actions.Action}s
  * for a configured target is called "analysis". The analysis of a configured target is composed of
- * the following steps (which process is orchestrated by
- * {@link com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction}):
+ * the following steps (which process is orchestrated by {@link
+ * com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction}):
+ *
  * <ol>
- *   <li>The corresponding {@link com.google.devtools.build.lib.packages.Target} is loaded, i.e.
- *       the BUILD file is parsed.</li>
- *   <li>Its direct dependencies are analyzed, during which in turn indirect dependencies are
- *       also analyzed.</li>
+ *   <li>The corresponding {@link com.google.devtools.build.lib.packages.Target} is loaded, i.e. the
+ *       BUILD file is parsed.
+ *   <li>Its direct dependencies are analyzed, during which in turn indirect dependencies are also
+ *       analyzed.
  *   <li>Aspects specified by the configured target are analyzed. These can be thought of as
- *       visitations of the transitive dependencies of the target. For more information, see
- *       {@link com.google.devtools.build.lib.packages.AspectClass}.
+ *       visitations of the transitive dependencies of the target. For more information, see {@link
+ *       com.google.devtools.build.lib.packages.AspectClass}.
  *   <li>The configured target and the actions it generates are created based on the data from the
- *       previous two steps.</li>
+ *       previous two steps.
  * </ol>
  *
  * Targets can be of three main kinds (plus a few special ones which are not important for
  * understanding the big picture):
+ *
  * <p>
- *   <li>Input and output files. These represent either a file that is in the source tree or a
- *       file produced by during the build. Not every file produced during the build has a
- *       corresponding output file target.</li>
- *   <li>Rules. These describe things a build actually does. Each rule has a class (e.g.
- *       <code>cc_binary</code>). Rule classes can be defined either in Skylark using the
- *       <code>rule()</code> function or in Java code by implementing
- *       {@link com.google.devtools.build.lib.analysis.RuleDefinition}.</li>
- * </p>
- * <p>During the analysis of a configured target, the following pieces of data are available:
- * <ul>
- *   <li>The corresponding target itself. This is necessary so that the analysis has access to e.g.
- *       the attributes a rule has in the BUILD file.</li>
- *   <li>The {@link com.google.devtools.build.lib.analysis.TransitiveInfoCollection}s of direct
- *       dependencies. They are used to gather information from the transitive closure, for example,
- *       the include path entries for C++ compilation or all the object files that need to be
- *       compiled into a C++ binary.</li>
- *   <li>The configuration, which is used to determine which compiler to use and to get access
- *       to some command line options of Bazel that influence analysis.</li>
- *   <li>Skyframe, for requesting arbitrary Skyframe nodes. This is an escape hatch that should be
- *       used when other mechanisms provided are not suitable and allows one to e.g. read arbitrary
- *       files. With great power...
- * </ul>
+ * <li>Input and output files. These represent either a file that is in the source tree or a file
+ *     produced by during the build. Not every file produced during the build has a corresponding
+ *     output file target.
+ * <li>Rules. These describe things a build actually does. Each rule has a class (e.g. <code>
+ *     cc_binary</code>). Rule classes can be defined either in Skylark using the <code>rule()
+ *     </code> function or in Java code by implementing {@link
+ *     com.google.devtools.build.lib.analysis.RuleDefinition}.
  *
- * <p>Analysis of non-rule configured targets is special-cased and is not covered here.
+ *     <p>During the analysis of a configured target, the following pieces of data are available:
  *
- * <p>The analysis of a rule itself is done by implementations {@link RuleConfiguredTargetFactory}
- * (there should be one for each rule class). The data above is available using the
- * {@link RuleContext} argument passed into its create() method. It should
- * result in three things:
- * <ul>
- *   <li>A set of actions. These should be passed to
- *   {@link RuleContext#registerAction(ActionAnalysisMetadata...)}, although for more
- *       common cases (e.g. {@link com.google.devtools.build.lib.analysis.actions.SpawnAction}),
- *       shortcuts are provided.</li>
- *   <li>A set of artifacts (files produced by actions). These should be created using methods of
- *       {@link RuleContext}. Each artifact thus created must have a generating action.</li>
- *   <li>A set of {@link com.google.devtools.build.lib.analysis.TransitiveInfoProvider}s that are
- *       passed on to direct dependencies. These must be registered using
- *       {@link com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder#add(
- *       Class, com.google.devtools.build.lib.analysis.TransitiveInfoProvider)}
- *       </li>
- * </ul>
+ *     <ul>
+ *       <li>The corresponding target itself. This is necessary so that the analysis has access to
+ *           e.g. the attributes a rule has in the BUILD file.
+ *       <li>The {@link com.google.devtools.build.lib.analysis.TransitiveInfoCollection}s of direct
+ *           dependencies. They are used to gather information from the transitive closure, for
+ *           example, the include path entries for C++ compilation or all the object files that need
+ *           to be compiled into a C++ binary.
+ *       <li>The configuration, which is used to determine which compiler to use and to get access
+ *           to some command line options of Bazel that influence analysis.
+ *       <li>Skyframe, for requesting arbitrary Skyframe nodes. This is an escape hatch that should
+ *           be used when other mechanisms provided are not suitable and allows one to e.g. read
+ *           arbitrary files. With great power...
+ *     </ul>
  *
- * <p>Configured targets are currently allowed to create artifacts at any exec path. It would be
- * better if they could be constrained to a subtree based on the label of the configured target,
- * but this is currently not feasible because multiple rules violate this constraint and the
- * output format is part of its interface.
+ *     <p>Analysis of non-rule configured targets is special-cased and is not covered here.
  *
- * <p>In principle, multiple configured targets should not create actions with conflicting
- * outputs. There are still a few exceptions to this rule that are slated to be eventually
- * removed, we have provisions to handle this case (Action instances that share at least one
- * output file are required to be exactly the same), but this does put some pressure on the design
- * and we are eventually planning to eliminate this option.
+ *     <p>The analysis of a rule itself is done by implementations {@link
+ *     RuleConfiguredTargetFactory} (there should be one for each rule class). The data above is
+ *     available using the {@link RuleContext} argument passed into its create() method. It should
+ *     result in three things:
  *
- * <p>These restrictions together make it possible to:
- * <ul>
- * <li>Correctly cache the analysis phase; by tightly constraining what a configured target is
- * allowed to access and what it is not, we can know when it needs to invalidate a particular
- * one and when it can reuse an already existing one.
- * <li>Serialize / deserialize individual configured targets at will, making it possible for
- * example to swap out part of the analysis state if there is memory pressure or to move them in
- * persistent storage so that the state can be reconstructed at a different time or in a
- * different process. The stretch goal is to eventually facilitate cross-user caching of this
- * information.
- * </ul>
+ *     <ul>
+ *       <li>A set of actions. These should be passed to {@link
+ *           RuleContext#registerAction(ActionAnalysisMetadata...)}, although for more common cases
+ *           (e.g. {@link com.google.devtools.build.lib.analysis.actions.SpawnAction}), shortcuts
+ *           are provided.
+ *       <li>A set of artifacts (files produced by actions). These should be created using methods
+ *           of {@link RuleContext}. Each artifact thus created must have a generating action.
+ *       <li>A set of {@link com.google.devtools.build.lib.analysis.TransitiveInfoProvider}s that
+ *           are passed on to direct dependencies. These must be registered using {@link
+ *           com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder#add( Class,
+ *           com.google.devtools.build.lib.analysis.TransitiveInfoProvider)}
+ *     </ul>
  *
+ *     <p>Configured targets are currently allowed to create artifacts at any exec path. It would be
+ *     better if they could be constrained to a subtree based on the label of the configured target,
+ *     but this is currently not feasible because multiple rules violate this constraint and the
+ *     output format is part of its interface.
+ *
+ *     <p>In principle, multiple configured targets should not create actions with conflicting
+ *     outputs. There are still a few exceptions to this rule that are slated to be eventually
+ *     removed, we have provisions to handle this case (Action instances that share at least one
+ *     output file are required to be exactly the same), but this does put some pressure on the
+ *     design and we are eventually planning to eliminate this option.
+ *
+ *     <p>These restrictions together make it possible to:
+ *
+ *     <ul>
+ *       <li>Correctly cache the analysis phase; by tightly constraining what a configured target is
+ *           allowed to access and what it is not, we can know when it needs to invalidate a
+ *           particular one and when it can reuse an already existing one.
+ *       <li>Serialize / deserialize individual configured targets at will, making it possible for
+ *           example to swap out part of the analysis state if there is memory pressure or to move
+ *           them in persistent storage so that the state can be reconstructed at a different time
+ *           or in a different process. The stretch goal is to eventually facilitate cross-user
+ *           caching of this information.
+ *     </ul>
  */
 public interface RuleConfiguredTargetFactory
-    extends RuleClass.ConfiguredTargetFactory<ConfiguredTarget, RuleContext> {
-}
+    extends RuleClass.ConfiguredTargetFactory<
+        ConfiguredTarget, RuleContext, ActionConflictException> {}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkTreeAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkTreeAction.java
index 60d75e1..87e2130 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkTreeAction.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/SymlinkTreeAction.java
@@ -24,6 +24,7 @@
 import com.google.devtools.build.lib.actions.ActionResult;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.util.Fingerprint;
 
 /**
@@ -31,6 +32,7 @@
  * Used to generate runfiles and fileset symlink farms.
  */
 @Immutable
+@AutoCodec
 public final class SymlinkTreeAction extends AbstractAction {
 
   private static final String GUID = "63412bda-4026-4c8e-a3ad-7deb397728d4";
@@ -51,6 +53,7 @@
    * @param filesetTree true if this is fileset symlink tree,
    * @param enableRunfiles true is the actual symlink tree needs to be created.
    */
+  @AutoCodec.Instantiator
   public SymlinkTreeAction(
       ActionOwner owner,
       Artifact inputManifest,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java
index 770fee7..54b271f 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/configuredtargets/RuleConfiguredTarget.java
@@ -19,6 +19,8 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Interner;
+import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -46,6 +48,8 @@
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkPrinter;
 import com.google.devtools.build.lib.syntax.Printer;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 import javax.annotation.Nullable;
 
@@ -58,6 +62,8 @@
  */
 @AutoCodec
 public final class RuleConfiguredTarget extends AbstractConfiguredTarget {
+  private static final String ACTIONS_FIELD_NAME = "actions";
+
   /**
    * The configuration transition for an attribute through which a prerequisite
    * is requested.
@@ -80,9 +86,12 @@
   private static final Interner<ImmutableSet<ConfiguredTargetKey>> IMPLICIT_DEPS_INTERNER =
       BlazeInterners.newWeakInterner();
 
+  private boolean actionsAccessible = true;
   private final TransitiveInfoProviderMap providers;
   private final ImmutableMap<Label, ConfigMatchingProvider> configConditions;
   private final String ruleClassString;
+  private final ArrayList<ActionAnalysisMetadata> actions;
+  private final ImmutableMap<Artifact, Integer> generatingActionIndex;
 
   @Instantiator
   @VisibleForSerialization
@@ -93,8 +102,11 @@
       TransitiveInfoProviderMap providers,
       ImmutableMap<Label, ConfigMatchingProvider> configConditions,
       ImmutableSet<ConfiguredTargetKey> implicitDeps,
-      String ruleClassString) {
+      String ruleClassString,
+      List<ActionAnalysisMetadata> actions,
+      ImmutableMap<Artifact, Integer> generatingActionIndex) {
     super(label, configuration, visibility);
+
     // We don't use ImmutableMap.Builder here to allow augmenting the initial list of 'default'
     // providers by passing them in.
     TransitiveInfoProviderMapBuilder providerBuilder =
@@ -115,9 +127,15 @@
     this.configConditions = configConditions;
     this.implicitDeps = IMPLICIT_DEPS_INTERNER.intern(implicitDeps);
     this.ruleClassString = ruleClassString;
+    this.actions = new ArrayList<>(actions);
+    this.generatingActionIndex = generatingActionIndex;
   }
 
-  public RuleConfiguredTarget(RuleContext ruleContext, TransitiveInfoProviderMap providers) {
+  public RuleConfiguredTarget(
+      RuleContext ruleContext,
+      TransitiveInfoProviderMap providers,
+      List<? extends ActionAnalysisMetadata> actions,
+      ImmutableMap<Artifact, Integer> generatingActionIndex) {
     this(
         ruleContext.getLabel(),
         ruleContext.getConfiguration(),
@@ -125,7 +143,9 @@
         providers,
         ruleContext.getConfigConditions(),
         Util.findImplicitDeps(ruleContext),
-        ruleContext.getRule().getRuleClass());
+        ruleContext.getRule().getRuleClass(),
+        (List<ActionAnalysisMetadata>) actions,
+        generatingActionIndex);
 
     // If this rule is the run_under target, then check that we have an executable; note that
     // run_under is only set in the target configuration, and the target must also be analyzed for
@@ -184,6 +204,7 @@
         result.accept((String) classAt);
       }
     }
+    result.accept(ACTIONS_FIELD_NAME);
   }
 
   @Override
@@ -193,6 +214,9 @@
 
   @Override
   protected Object rawGetSkylarkProvider(String providerKey) {
+    if (providerKey.equals(ACTIONS_FIELD_NAME)) {
+      return actionsAccessible ? actions : ImmutableList.of();
+    }
     return providers.getProvider(providerKey);
   }
 
@@ -217,4 +241,22 @@
     printer.append(Joiner.on(", ").join(skylarkProviderKeyStrings.build()));
     printer.append("]>");
   }
+
+  /** Returns a list of actions that this configured target generated. */
+  public ArrayList<ActionAnalysisMetadata> getActions() {
+    return actions;
+  }
+
+  /**
+   * Returns a map where keys are artifacts that are action outputs of this rule, and values are the
+   * index of the action that generates that artifact.
+   */
+  public ImmutableMap<Artifact, Integer> getGeneratingActionIndex() {
+    return generatingActionIndex;
+  }
+
+  /** Disables accessing actions via a provider skylark interface. */
+  public void disableAcccesibleActions() {
+    this.actionsAccessible = false;
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java b/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java
index f31d26c..c0e8493 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/constraints/Environment.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.analysis.constraints;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -24,6 +25,7 @@
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.EnvironmentGroup;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 
 /**
  * Implementation for the environment rule.
@@ -31,7 +33,8 @@
 public class Environment implements RuleConfiguredTargetFactory {
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     // The main analysis work to do here is to simply fill in SupportedEnvironmentsProvider to
     // pass the environment itself to depending rules.
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java
index d22857e..f1aac64 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleConfiguredTargetUtil.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ActionsProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.DefaultInfo;
@@ -35,6 +36,7 @@
 import com.google.devtools.build.lib.packages.Info;
 import com.google.devtools.build.lib.packages.NativeProvider;
 import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.TargetUtils;
 import com.google.devtools.build.lib.skylarkinterface.SkylarkValue;
 import com.google.devtools.build.lib.syntax.BaseFunction;
@@ -69,14 +71,10 @@
   private static final ImmutableSet<String> DEFAULT_PROVIDER_FIELDS =
       ImmutableSet.of("files", "runfiles", "data_runfiles", "default_runfiles", "executable");
 
-  /**
-   * Create a Rule Configured Target from the ruleContext and the ruleImplementation.
-   */
+  /** Create a Rule Configured Target from the ruleContext and the ruleImplementation. */
   public static ConfiguredTarget buildRule(
-      RuleContext ruleContext,
-      BaseFunction ruleImplementation,
-      SkylarkSemantics skylarkSemantics)
-      throws InterruptedException {
+      RuleContext ruleContext, BaseFunction ruleImplementation, SkylarkSemantics skylarkSemantics)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     String expectFailure = ruleContext.attributes().get("expect_failure", Type.STRING);
     SkylarkRuleContext skylarkRuleContext = null;
     try (Mutability mutability = Mutability.create("configured target")) {
@@ -152,7 +150,7 @@
   }
 
   private static ConfiguredTarget createTarget(SkylarkRuleContext context, Object target)
-      throws EvalException {
+      throws EvalException, RuleErrorException, ActionConflictException {
     RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(
         context.getRuleContext());
     // Set the default files to build.
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuntime.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuntime.java
index a65dac4..4c96dbe 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/BazelPyRuntime.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.bazel.rules.python;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -34,7 +35,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSet<Artifact> files =
         PrerequisiteArtifacts.nestedSet(ruleContext, "files", Mode.TARGET);
     Artifact interpreter =
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
index 8150fea..85de9e9 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShBinary.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -42,7 +43,8 @@
       Template.forResource(ShBinary.class, "sh_stub_template_windows.txt");
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ImmutableList<Artifact> srcs = ruleContext.getPrerequisiteArtifacts("srcs", Mode.TARGET).list();
     if (srcs.size() != 1) {
       ruleContext.attributeError("srcs", "you must specify exactly one file in 'srcs'");
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java
index ce715e1..10fc471 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/sh/ShLibrary.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.bazel.rules.sh;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -30,7 +31,8 @@
 public class ShLibrary implements RuleConfiguredTargetFactory {
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSet<Artifact> filesToBuild = NestedSetBuilder.<Artifact>stableOrder()
         .addAll(ruleContext.getPrerequisiteArtifacts("srcs", Mode.TARGET).list())
         .addAll(ruleContext.getPrerequisiteArtifacts("deps", Mode.TARGET).list())
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
index 51db543..34e246f 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleClass.java
@@ -174,22 +174,23 @@
     }
   }
 
-  /**
-   * A factory or builder class for rule implementations.
-   */
-  public interface ConfiguredTargetFactory<TConfiguredTarget, TContext> {
+  /** A factory or builder class for rule implementations. */
+  public interface ConfiguredTargetFactory<
+      TConfiguredTarget, TContext, TActionConflictException extends Throwable> {
     /**
      * Returns a fully initialized configured target instance using the given context.
      *
      * @throws RuleErrorException if configured target creation could not be completed due to rule
-     *    errors
+     *     errors
+     * @throws TActionConflictException if there were conflicts during action registration
      */
-    TConfiguredTarget create(TContext ruleContext) throws InterruptedException, RuleErrorException;
+    TConfiguredTarget create(TContext ruleContext)
+        throws InterruptedException, RuleErrorException, TActionConflictException;
 
     /**
-     * Exception indicating that configured target creation could not be completed. Error messaging
-     * should be done via {@link RuleErrorConsumer}; this exception only interrupts configured
-     * target creation in cases where it can no longer continue.
+     * Exception indicating that configured target creation could not be completed. General error
+     * messaging should be done via {@link RuleErrorConsumer}; this exception only interrupts
+     * configured target creation in cases where it can no longer continue.
      */
     public static final class RuleErrorException extends Exception {}
   }
@@ -586,7 +587,7 @@
     private ImplicitOutputsFunction implicitOutputsFunction = ImplicitOutputsFunction.NONE;
     private RuleTransitionFactory transitionFactory;
     private RuleTransitionFactory outgoingTransitionFactory;
-    private ConfiguredTargetFactory<?, ?> configuredTargetFactory = null;
+    private ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory = null;
     private PredicateWithMessage<Rule> validityPredicate =
         PredicatesWithMessage.<Rule>alwaysTrue();
     private Predicate<String> preferredDependencyPredicate = Predicates.alwaysFalse();
@@ -911,7 +912,7 @@
       return this;
     }
 
-    public Builder factory(ConfiguredTargetFactory<?, ?> factory) {
+    public Builder factory(ConfiguredTargetFactory<?, ?, ?> factory) {
       this.configuredTargetFactory = factory;
       return this;
     }
@@ -1225,10 +1226,8 @@
    */
   private final RuleTransitionFactory outgoingTransitionFactory;
 
-  /**
-   * The factory that creates configured targets from this rule.
-   */
-  private final ConfiguredTargetFactory<?, ?> configuredTargetFactory;
+  /** The factory that creates configured targets from this rule. */
+  private final ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory;
 
   /**
    * The constraint the package name of the rule instance must fulfill
@@ -1318,7 +1317,7 @@
       boolean isConfigMatcher,
       RuleTransitionFactory transitionFactory,
       RuleTransitionFactory outgoingRuleTransitionFactory,
-      ConfiguredTargetFactory<?, ?> configuredTargetFactory,
+      ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory,
       PredicateWithMessage<Rule> validityPredicate,
       Predicate<String> preferredDependencyPredicate,
       AdvertisedProviderSet advertisedProviders,
@@ -1421,8 +1420,9 @@
   }
 
   @SuppressWarnings("unchecked")
-  public <CT, RC> ConfiguredTargetFactory<CT, RC> getConfiguredTargetFactory() {
-    return (ConfiguredTargetFactory<CT, RC>) configuredTargetFactory;
+  public <CT, RC, ACE extends Throwable>
+      ConfiguredTargetFactory<CT, RC, ACE> getConfiguredTargetFactory() {
+    return (ConfiguredTargetFactory<CT, RC, ACE>) configuredTargetFactory;
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/rules/Alias.java b/src/main/java/com/google/devtools/build/lib/rules/Alias.java
index 364f674..ad57397 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/Alias.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/Alias.java
@@ -18,6 +18,7 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -38,7 +39,7 @@
 public class Alias implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite("actual", Mode.TARGET);
     return new AliasConfiguredTarget(
         ruleContext,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/ToolchainType.java b/src/main/java/com/google/devtools/build/lib/rules/ToolchainType.java
index 6ddc531..d0d25b2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/ToolchainType.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/ToolchainType.java
@@ -16,6 +16,7 @@
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.PlatformConfiguration;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -62,7 +63,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     if (fragmentMap == null && fragmentMapFromRuleContext != null) {
       this.fragmentMap = fragmentMapFromRuleContext.apply(ruleContext);
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
index 935844b..d0e1f37 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AarImport.java
@@ -16,6 +16,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -60,7 +61,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     AndroidSdkProvider.verifyPresence(ruleContext);
 
     RuleConfiguredTargetBuilder ruleBuilder = new RuleConfiguredTargetBuilder(ruleContext);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index d70f57b..44a171a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -31,6 +31,7 @@
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifact;
 import com.google.devtools.build.lib.actions.CommandLine;
 import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.ParamFileInfo;
 import com.google.devtools.build.lib.actions.ParameterFile;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -93,7 +94,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     CppSemantics cppSemantics = createCppSemantics();
     JavaSemantics javaSemantics = createJavaSemantics();
     AndroidSemantics androidSemantics = createAndroidSemantics();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDevice.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDevice.java
index f637f81..68a4f95 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDevice.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDevice.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Streams;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.ResourceSet;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
@@ -83,7 +84,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     checkWhitelist(ruleContext);
     Artifact executable = ruleContext.createOutputArtifact();
     Artifact metadata =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java
index fa3424d..ce7ed56 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidDeviceScriptFixture.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -33,7 +34,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     Artifact fixtureScript = getFixtureScript(ruleContext);
     return new RuleConfiguredTargetBuilder(ruleContext)
         .setFilesToBuild(NestedSetBuilder.<Artifact>stableOrder().add(fixtureScript).build())
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java
index 9996d47..c8fbbe0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidHostServiceFixture.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.rules.android;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -31,7 +32,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     RuleConfiguredTargetBuilder ruleBuilder = new RuleConfiguredTargetBuilder(ruleContext);
     NestedSet<Artifact> supportApks = AndroidCommon.getSupportApks(ruleContext);
     FilesToRunProvider executable = ruleContext.getExecutablePrerequisite("executable", Mode.HOST);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationTest.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationTest.java
index 6a1523c..abc34c1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidInstrumentationTest.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Streams;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -63,7 +64,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     validateRuleContext(ruleContext);
 
     // The wrapper script that invokes the test entry point.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
index 6173e3c..21fcb61 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLibrary.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -109,7 +110,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     validateRuleContext(ruleContext);
     JavaSemantics javaSemantics = createJavaSemantics();
     AndroidSemantics androidSemantics = createAndroidSemantics();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
index 11dc93e..21cee09 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -18,6 +18,7 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -71,7 +72,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     ruleContext.checkSrcsSamePackage(true);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java
index e8f7051..6ba38dd 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.rules.android;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -32,7 +33,7 @@
 public class AndroidSdk implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     // If the user didn't specify --proguard_top, go with the proguard attribute in the android_sdk
     // rule. Otherwise, use what she told us to.
     FilesToRunProvider proguard =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidToolsDefaultsJar.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidToolsDefaultsJar.java
index 36a889f..1afc07f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidToolsDefaultsJar.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidToolsDefaultsJar.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.rules.android;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -37,7 +38,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     Artifact androidJar = AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar();
 
     return new RuleConfiguredTargetBuilder(ruleContext)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/BUILD b/src/main/java/com/google/devtools/build/lib/rules/apple/BUILD
index a40e8f8..4ad39bc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/BUILD
@@ -17,6 +17,7 @@
         "//src/main/java/com/google/devtools/build/lib:packages-internal",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:syntax",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/analysis/skylark/annotations",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/concurrent",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java
index abb00c0..d9ae4a0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfig.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Streams;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -50,7 +51,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     AppleConfiguration appleConfig = ruleContext.getFragment(AppleConfiguration.class);
     AppleCommandLineOptions appleOptions = appleConfig.getOptions();
     XcodeVersionRuleData defaultVersion = ruleContext.getPrerequisite(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.java
index a2d89f2..677ff91 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeConfigAlias.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.rules.apple;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -38,7 +39,7 @@
 public class XcodeConfigAlias implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ConfiguredTarget actual = (ConfiguredTarget) ruleContext.getPrerequisite(
         XcodeConfigRule.XCODE_CONFIG_ATTR_NAME, Mode.TARGET);
     return new AliasConfiguredTarget(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersion.java b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersion.java
index f341cbc..6529c5b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersion.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/apple/XcodeVersion.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.apple;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -27,7 +28,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     XcodeVersionRuleData ruleData =
         new XcodeVersionRuleData(ruleContext.getLabel(), ruleContext.getRule());
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java
index 175588c..4326d4a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlag.java
@@ -25,6 +25,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Multiset;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -37,7 +38,6 @@
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.Attribute.ComputedDefault;
 import com.google.devtools.build.lib.packages.AttributeMap;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.syntax.Printer;
 import java.util.List;
 import java.util.Optional;
@@ -89,7 +89,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     if (!ConfigFeatureFlag.isAvailable(ruleContext)) {
       ruleContext.ruleError(
           String.format(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
index 701c11a..1d475f9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/config/ConfigSetting.java
@@ -28,6 +28,7 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Multiset;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
@@ -50,7 +51,6 @@
 import com.google.devtools.build.lib.packages.AttributeMap;
 import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.packages.RuleErrorConsumer;
 import com.google.devtools.build.lib.rules.config.ConfigRuleClasses.ConfigSettingRule;
 import com.google.devtools.build.lib.syntax.Type;
@@ -73,7 +73,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     AttributeMap attributes = NonconfigurableAttributeMapper.of(ruleContext.getRule());
     // Get the built-in Blaze flag settings that match this rule.
     ImmutableMultimap<String, String> nativeFlagSettings =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
index 351644e..36c281f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcBinary.java
@@ -23,6 +23,7 @@
 import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ExecutionRequirements;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.ParamFileInfo;
 import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -161,12 +162,12 @@
 
   @Override
   public ConfiguredTarget create(RuleContext context)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     return CcBinary.init(semantics, context, /*fake =*/ false);
   }
 
   public static ConfiguredTarget init(CppSemantics semantics, RuleContext ruleContext, boolean fake)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ruleContext.checkSrcsSamePackage(true);
 
     CcCommon common = new CcCommon(ruleContext);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
index 031555b..3a100a7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcImport.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -43,7 +44,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws RuleErrorException, InterruptedException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     Artifact staticLibrary = ruleContext.getPrerequisiteArtifact("static_library", Mode.TARGET);
     Artifact sharedLibrary = ruleContext.getPrerequisiteArtifact("shared_library", Mode.TARGET);
     Artifact interfaceLibrary =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
index 3463012..84f86c7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcLibrary.java
@@ -19,6 +19,7 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.MakeVariableSupplier.MapBackedMakeVariableSupplier;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -89,7 +90,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext context)
-      throws RuleErrorException, InterruptedException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(context);
     LinkTargetType staticLinkType = getStaticLinkType(context);
     boolean linkStatic = context.attributes().get("linkstatic", Type.BOOLEAN);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcTest.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcTest.java
index 8af5f16..4478b63 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcTest.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.cpp;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -31,7 +32,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext context)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     return CcBinary.init(semantics, context, /*fake =*/ false);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
index 11628db..a62abb5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchain.java
@@ -21,6 +21,7 @@
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Actions;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AnalysisUtils;
 import com.google.devtools.build.lib.analysis.CompilationHelper;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -303,7 +304,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws RuleErrorException, InterruptedException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     TransitiveInfoCollection lipoContextCollector =
         ruleContext.getPrerequisite(
             TransitiveLipoInfoProvider.LIPO_CONTEXT_COLLECTOR, Mode.DONT_CHECK);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainAlias.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainAlias.java
index dd40149..57837f6 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainAlias.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainAlias.java
@@ -18,6 +18,7 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -38,7 +39,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ConfiguredTarget actual =
         (ConfiguredTarget) ruleContext.getPrerequisite(":cc_toolchain", Mode.TARGET);
     return new AliasConfiguredTarget(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java
index e7d2089..59b560a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/CcToolchainSuite.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.rules.cpp;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -34,7 +35,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
     for (TransitiveInfoCollection dep : ruleContext.getPrerequisiteMap("toolchains").values()) {
       CcToolchainProvider provider =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
index da5d46b..91d76eb 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/cpp/proto/CcProtoLibrary.java
@@ -17,6 +17,7 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode.TARGET;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -29,7 +30,7 @@
 public class CcProtoLibrary implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     if (ruleContext.getPrerequisites("deps", TARGET).size() != 1) {
       ruleContext.throwWithAttributeError(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java
index 82325c8..afbb2da 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ActionListener.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -36,7 +37,8 @@
  */
 public final class ActionListener implements RuleConfiguredTargetFactory {
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     // This rule doesn't produce any output when listed as a build target.
     // Only when used via the --experimental_action_listener flag,
     // this rule instructs the build system to add additional outputs.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java
index 1eb434e..b2e029d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/extra/ExtraActionFactory.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.Lists;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.CommandHelper;
 import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -39,7 +40,8 @@
  */
 public final class ExtraActionFactory implements RuleConfiguredTargetFactory {
   @Override
-  public ConfiguredTarget create(RuleContext context) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext context)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     // This rule doesn't produce any output when listed as a build target.
     // Only when used via the --experimental_action_listener flag,
     // this rule instructs the build system to add additional outputs.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/filegroup/Filegroup.java b/src/main/java/com/google/devtools/build/lib/rules/filegroup/Filegroup.java
index e8b3309..805a12b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/filegroup/Filegroup.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/filegroup/Filegroup.java
@@ -18,6 +18,7 @@
 
 import com.google.devtools.build.lib.actions.Actions;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.CompilationHelper;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.MiddlemanProvider;
@@ -51,7 +52,8 @@
       "Output group %s is not permitted for " + "reference in filegroups.";
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     String outputGroupName = ruleContext.attributes().get("output_group", Type.STRING);
 
     if (outputGroupName.endsWith(INTERNAL_SUFFIX)) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
index b6619a9..7b8ab12 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genquery/GenQuery.java
@@ -26,6 +26,7 @@
 import com.google.devtools.build.lib.actions.ActionKeyContext;
 import com.google.devtools.build.lib.actions.ActionOwner;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -104,7 +105,7 @@
   @Override
   @Nullable
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     Artifact outputArtifact = ruleContext.createOutputArtifact();
 
     // The query string
diff --git a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
index 74a2bd6..33e52c0 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/genrule/GenRuleBase.java
@@ -22,6 +22,7 @@
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.CommandLine;
 import com.google.devtools.build.lib.actions.CompositeRunfilesSupplier;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.CommandHelper;
 import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
@@ -103,7 +104,7 @@
    * Updates the {@link RuleConfiguredTargetBuilder} that is used for this rule.
    *
    * <p>GenRule implementations can override this method to enhance and update the builder without
-   * needing to entirely override the {@link #create} method.
+   * needing to entirely override the {@link ConfiguredTargetFactory#create} method.
    */
   protected RuleConfiguredTargetBuilder updateBuilder(
       RuleConfiguredTargetBuilder builder,
@@ -114,7 +115,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws RuleErrorException, InterruptedException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSet<Artifact> filesToBuild =
         NestedSetBuilder.wrap(Order.STABLE_ORDER, ruleContext.getOutputArtifacts());
     NestedSetBuilder<Artifact> resolvedSrcsBuilder = NestedSetBuilder.stableOrder();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
index 9967d20..870c3b5 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -70,7 +71,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     final JavaCommon common = new JavaCommon(ruleContext, semantics);
     DeployArchiveBuilder deployArchiveBuilder =  new DeployArchiveBuilder(semantics, ruleContext);
     Runfiles.Builder runfilesBuilder = new Runfiles.Builder(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaImport.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaImport.java
index 79e2711..0ff1762 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaImport.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
@@ -50,7 +51,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ImmutableList<Artifact> srcJars = ImmutableList.of();
     ImmutableList<Artifact> jars = collectJars(ruleContext);
     Artifact srcJar = ruleContext.getPrerequisiteArtifact("srcjar", Mode.TARGET);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
index ed5f32c..f329e83 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaLibrary.java
@@ -16,6 +16,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -45,7 +46,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     JavaCommon common = new JavaCommon(ruleContext, semantics);
     return init(
         ruleContext,
@@ -55,9 +56,11 @@
   }
 
   final ConfiguredTarget init(
-      RuleContext ruleContext, final JavaCommon common, boolean includeGeneratedExtensionRegistry,
+      RuleContext ruleContext,
+      final JavaCommon common,
+      boolean includeGeneratedExtensionRegistry,
       boolean isJavaPluginRule)
-      throws InterruptedException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     JavaTargetAttributes.Builder attributesBuilder = common.initCommon();
 
     // Collect the transitive dependencies.
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java
index 649957c..3ea3935 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPackageConfiguration.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.rules.java;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.PackageSpecificationProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -32,7 +33,8 @@
 public class JavaPackageConfiguration implements RuleConfiguredTargetFactory {
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     List<PackageSpecificationProvider> packages =
         ImmutableList.copyOf(
             ruleContext.getPrerequisites(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPlugin.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPlugin.java
index f593fd9..d07ee35 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaPlugin.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaPlugin.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.rules.java;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -30,7 +31,7 @@
 
   @Override
   public final ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     return new JavaLibrary(semantics)
         .init(
             ruleContext,
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java
index c060a49..54f2c7d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntime.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Actions;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.CompilationHelper;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.PrerequisiteArtifacts;
@@ -40,7 +41,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSet<Artifact> filesToBuild =
         PrerequisiteArtifacts.nestedSet(ruleContext, "srcs", Mode.TARGET);
     PathFragment javaHome = defaultJavaHome(ruleContext.getLabel());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeAlias.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeAlias.java
index ce12aee..181e810 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeAlias.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeAlias.java
@@ -17,6 +17,7 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
@@ -38,7 +39,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     // Sadly, we can't use an AliasConfiguredTarget here because we need to be prepared for the case
     // when --javabase is not a label. For the time being.
     TransitiveInfoCollection runtime = ruleContext.getPrerequisite(":jvm", Mode.TARGET);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java
index e0d2a77d..f1c895f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaRuntimeSuite.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.java;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -28,7 +29,7 @@
 public class JavaRuntimeSuite implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     TransitiveInfoCollection runtime =
         ruleContext.getPrerequisiteMap("runtimes").get(ruleContext.getConfiguration().getCpu());
     if (runtime == null) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
index faa16d1..eb8aa8b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -53,7 +54,8 @@
   }
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ImmutableList<String> javacopts = getJavacOpts(ruleContext);
     NestedSet<Artifact> bootclasspath = PrerequisiteArtifacts.nestedSet(
         ruleContext, "bootclasspath", Mode.HOST);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainAlias.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainAlias.java
index d89ea11..ff12fc1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainAlias.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainAlias.java
@@ -18,6 +18,7 @@
 import static com.google.devtools.build.lib.packages.BuildType.LABEL;
 
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -38,7 +39,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ConfiguredTarget actual =
         (ConfiguredTarget) ruleContext.getPrerequisite(":java_toolchain", Mode.TARGET);
     return new AliasConfiguredTarget(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoLibrary.java
index e92896e..89a3d57 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaLiteProtoLibrary.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMultimap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -49,7 +50,7 @@
 
   @Override
   public ConfiguredTarget create(final RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     Iterable<JavaProtoLibraryAspectProvider> javaProtoLibraryAspectProviders =
         ruleContext.getPrerequisites("deps", Mode.TARGET, JavaProtoLibraryAspectProvider.class);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoLibrary.java
index 243251b..be7e19a 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/proto/JavaProtoLibrary.java
@@ -21,6 +21,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.OutputGroupInfo;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -44,7 +45,7 @@
 
   @Override
   public ConfiguredTarget create(final RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     Iterable<JavaProtoLibraryAspectProvider> javaProtoLibraryAspectProviders =
         ruleContext.getPrerequisites("deps", TARGET, JavaProtoLibraryAspectProvider.class);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
index cb61b80..be2a839 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleBinary.java
@@ -27,6 +27,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -114,7 +115,7 @@
 
   @Override
   public final ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     AppleBinaryOutput appleBinaryOutput = linkMultiArchBinary(ruleContext);
 
     return ruleConfiguredTargetFromProvider(ruleContext, appleBinaryOutput);
@@ -131,7 +132,7 @@
    * @return a tuple containing all necessary information about the linked binary
    */
   public static AppleBinaryOutput linkMultiArchBinary(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     MultiArchSplitTransitionProvider.validateMinimumOs(ruleContext);
     PlatformType platformType = MultiArchSplitTransitionProvider.getPlatformType(ruleContext);
 
@@ -301,7 +302,8 @@
   }
 
   private static ConfiguredTarget ruleConfiguredTargetFromProvider(
-      RuleContext ruleContext, AppleBinaryOutput appleBinaryOutput) throws RuleErrorException {
+      RuleContext ruleContext, AppleBinaryOutput appleBinaryOutput)
+      throws RuleErrorException, ActionConflictException {
     NativeInfo nativeInfo = appleBinaryOutput.getBinaryInfoProvider();
     AppleConfiguration appleConfiguration = ruleContext.getFragment(AppleConfiguration.class);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java
index fa2cee2..dfbcaec 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleSkylarkCommon.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleContext;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -497,7 +498,7 @@
       RuleContext ruleContext = skylarkRuleContext.getRuleContext();
       AppleBinaryOutput appleBinaryOutput = AppleBinary.linkMultiArchBinary(ruleContext);
       return appleBinaryOutput.getBinaryInfoProvider();
-    } catch (RuleErrorException exception) {
+    } catch (RuleErrorException | ActionConflictException exception) {
       throw new EvalException(null, exception);
     }
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java
index 49cc884..ab1f93e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStaticLibrary.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -71,7 +72,7 @@
 
   @Override
   public final ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     MultiArchSplitTransitionProvider.validateMinimumOs(ruleContext);
     PlatformType platformType = MultiArchSplitTransitionProvider.getPlatformType(ruleContext);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStubBinary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStubBinary.java
index e73c665..e72b47c 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStubBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/AppleStubBinary.java
@@ -22,6 +22,7 @@
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfigurationMakeVariableContext;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -104,7 +105,7 @@
 
   @Override
   public final ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     MultiArchSplitTransitionProvider.validateMinimumOs(ruleContext);
     PlatformType platformType = MultiArchSplitTransitionProvider.getPlatformType(ruleContext);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/IosDevice.java b/src/main/java/com/google/devtools/build/lib/rules/objc/IosDevice.java
index 92d02a8..378e63b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/IosDevice.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/IosDevice.java
@@ -17,6 +17,7 @@
 import static com.google.devtools.build.lib.syntax.Type.STRING;
 
 import com.google.common.base.Strings;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -34,7 +35,7 @@
 public final class IosDevice implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext context)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     context.ruleWarning(
         "This rule is deprecated. Please use the new Apple build rules "
             + "(https://github.com/bazelbuild/rules_apple) to build Apple targets.");
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java
index 69e42c3..83a35b9 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/J2ObjcLibrary.java
@@ -20,6 +20,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -59,7 +60,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     checkAttributes(ruleContext);
 
     if (ruleContext.hasErrors()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundle.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundle.java
index efc3596..12b7998 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundle.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundle.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -31,7 +32,7 @@
 public class ObjcBundle implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ObjcCommon common = new ObjcCommon.Builder(ruleContext).build();
 
     ImmutableList<Artifact> bundleImports = ruleContext
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java
index 328b212..3088b5d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcBundleLibrary.java
@@ -20,6 +20,7 @@
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -51,7 +52,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ObjcCommon common = common(ruleContext);
     Bundling bundling = bundling(ruleContext, common);
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFramework.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFramework.java
index 76b9fc8..baad025 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFramework.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcFramework.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -34,7 +35,7 @@
 public class ObjcFramework implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     CompilationAttributes compilationAttributes =
         CompilationAttributes.Builder.fromRuleContext(ruleContext).build();
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
index 9f2a169..c01a04f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcImport.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.rules.objc;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -30,7 +31,7 @@
 public class ObjcImport implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ObjcCommon common =
         new ObjcCommon.Builder(ruleContext)
             .setCompilationAttributes(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
index bebacd8..0fa2870 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcLibrary.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.rules.objc;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -59,7 +60,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     validateAttributes(ruleContext);
 
     ObjcCommon common = common(ruleContext);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java
index 5fa5a1d..67292e32 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/objc/ObjcProtoLibrary.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -30,13 +31,13 @@
 public class ObjcProtoLibrary implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(final RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     new ProtoAttributes(ruleContext).validate();
     return createProtobufTarget(ruleContext);
   }
 
   private ConfiguredTarget createProtobufTarget(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSetBuilder<Artifact> filesToBuild = NestedSetBuilder.stableOrder();
 
     Iterable<ProtoSourcesProvider> protoProviders =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/BUILD b/src/main/java/com/google/devtools/build/lib/rules/platform/BUILD
index c564fce..f398be1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/BUILD
@@ -18,6 +18,7 @@
         "//src/main/java/com/google/devtools/build/lib:core-rules",
         "//src/main/java/com/google/devtools/build/lib:packages",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/analysis/platform",
         "//src/main/java/com/google/devtools/build/lib/analysis/platform:utils",
         "//third_party:guava",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintSetting.java b/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintSetting.java
index 3723a88..d9ddbaf 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintSetting.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintSetting.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.platform;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -31,7 +32,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     return new RuleConfiguredTargetBuilder(ruleContext)
         .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintValue.java b/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintValue.java
index 036ccf6..98d625f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintValue.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/ConstraintValue.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.platform;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -31,7 +32,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     ConstraintSettingInfo constraint =
         PlatformProviderUtils.constraintSetting(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java b/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java
index 07196bb..2cab122 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/Platform.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.rules.platform;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -36,7 +37,7 @@
 public class Platform implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     PlatformInfo.Builder platformBuilder = PlatformInfo.builder().setLabel(ruleContext.getLabel());
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/platform/Toolchain.java b/src/main/java/com/google/devtools/build/lib/rules/platform/Toolchain.java
index 28a4c57..0a407fc 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/platform/Toolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/platform/Toolchain.java
@@ -15,6 +15,7 @@
 package com.google.devtools.build.lib.rules.platform;
 
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -34,7 +35,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
 
     Label toolchainType =
         ruleContext.attributes().get(ToolchainRule.TOOLCHAIN_TYPE_ATTR, BuildType.NODEP_LABEL);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibrary.java
index d1cd914..3843842 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibrary.java
@@ -20,6 +20,7 @@
 import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -35,7 +36,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     ImmutableList<Artifact> protoSources =
         ruleContext.getPrerequisiteArtifacts("srcs", TARGET).list();
     NestedSet<Artifact> checkDepsProtoSources =
diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchain.java
index e76736c..d045ad1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchain.java
@@ -19,6 +19,7 @@
 import static com.google.devtools.build.lib.collect.nestedset.Order.STABLE_ORDER;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.FileProvider;
 import com.google.devtools.build.lib.analysis.FilesToRunProvider;
@@ -34,7 +35,7 @@
 public class ProtoLangToolchain implements RuleConfiguredTargetFactory {
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     NestedSetBuilder<Artifact> blacklistedProtos = NestedSetBuilder.stableOrder();
     for (FileProvider protos :
         ruleContext.getPrerequisites("blacklisted_protos", TARGET, FileProvider.class)) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java
index b2ef88d..8415d17 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyBinary.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.rules.python;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -44,7 +45,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     PyCommon common = new PyCommon(ruleContext);
     common.initCommon(common.getDefaultPythonVersion());
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyLibrary.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyLibrary.java
index f41d99b..43f33f7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PyLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyLibrary.java
@@ -14,6 +14,7 @@
 package com.google.devtools.build.lib.rules.python;
 
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -43,7 +44,8 @@
   protected abstract PythonSemantics createSemantics();
 
   @Override
-  public ConfiguredTarget create(final RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(final RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     PythonSemantics semantics = createSemantics();
     PyCommon common = new PyCommon(ruleContext);
     common.initCommon(common.getDefaultPythonVersion());
diff --git a/src/main/java/com/google/devtools/build/lib/rules/python/PyTest.java b/src/main/java/com/google/devtools/build/lib/rules/python/PyTest.java
index f071108..b60b5a2 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/python/PyTest.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/python/PyTest.java
@@ -13,11 +13,11 @@
 // limitations under the License.
 package com.google.devtools.build.lib.rules.python;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 import com.google.devtools.build.lib.syntax.Type;
 
 /**
@@ -32,7 +32,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     PythonSemantics semantics = createSemantics();
     PyCommon common = new PyCommon(ruleContext);
     common.initCommon(getDefaultPythonVersion(ruleContext));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java b/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java
index 4f9edc3..2a6b4d1 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/Bind.java
@@ -16,6 +16,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.AliasProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -37,7 +38,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     if (ruleContext.getPrerequisite("actual", Mode.TARGET) == null) {
       ruleContext.ruleError(String.format("The external label '%s' is not bound to anything",
           ruleContext.getLabel()));
diff --git a/src/main/java/com/google/devtools/build/lib/rules/repository/WorkspaceConfiguredTargetFactory.java b/src/main/java/com/google/devtools/build/lib/rules/repository/WorkspaceConfiguredTargetFactory.java
index 8a51c46..802b499 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/repository/WorkspaceConfiguredTargetFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/repository/WorkspaceConfiguredTargetFactory.java
@@ -14,12 +14,12 @@
 
 package com.google.devtools.build.lib.rules.repository;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
 import com.google.devtools.build.lib.analysis.RunfilesProvider;
-import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
 
 /**
  * Implementation of workspace rules.  Generally, these don't have any providers, since they
@@ -30,7 +30,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     return new RuleConfiguredTargetBuilder(ruleContext)
         .addProvider(RunfilesProvider.class, RunfilesProvider.EMPTY)
         .build();
diff --git a/src/main/java/com/google/devtools/build/lib/rules/test/TestSuite.java b/src/main/java/com/google/devtools/build/lib/rules/test/TestSuite.java
index 7a407c1..5767d83 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/test/TestSuite.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/test/TestSuite.java
@@ -15,6 +15,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -38,7 +39,8 @@
 public class TestSuite implements RuleConfiguredTargetFactory {
 
   @Override
-  public ConfiguredTarget create(RuleContext ruleContext) throws RuleErrorException {
+  public ConfiguredTarget create(RuleContext ruleContext)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     checkTestsAndSuites(ruleContext, "tests");
     if (ruleContext.hasErrors()) {
       return null;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionValue.java
index dd60938..3613787 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionValue.java
@@ -15,8 +15,8 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.concurrent.BlazeInterners;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
@@ -25,7 +25,7 @@
 /**
  * Value that stores expanded actions from ActionTemplate.
  */
-public final class ActionTemplateExpansionValue extends ActionLookupValue {
+public final class ActionTemplateExpansionValue extends BasicActionLookupValue {
   ActionTemplateExpansionValue(
       GeneratingActions generatingActions, boolean removeActionsAfterEvaluation) {
     super(generatingActions, removeActionsAfterEvaluation);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
index 08c8c06..116d186 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValue.java
@@ -19,8 +19,8 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.analysis.ConfiguredAspect;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.cmdline.Label;
@@ -42,7 +42,7 @@
 /**
  * An aspect in the context of the Skyframe graph.
  */
-public final class AspectValue extends ActionLookupValue {
+public final class AspectValue extends BasicActionLookupValue {
 
   /**
    * A base class for keys that have AspectValue as a Sky value.
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java
index 485a6a7..9232f7a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BuildInfoCollectionValue.java
@@ -15,8 +15,8 @@
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoCollection;
 import com.google.devtools.build.lib.analysis.buildinfo.BuildInfoFactory;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
@@ -30,7 +30,7 @@
  * Value that stores {@link BuildInfoCollection}s generated by {@link BuildInfoFactory} instances.
  * These collections are used during analysis (see {@code CachingAnalysisEnvironment}).
  */
-public class BuildInfoCollectionValue extends ActionLookupValue {
+public class BuildInfoCollectionValue extends BasicActionLookupValue {
   private final BuildInfoCollection collection;
 
   BuildInfoCollectionValue(
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 962f136..42b32c9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -37,6 +37,7 @@
 import com.google.devtools.build.lib.analysis.config.ConfigurationResolver;
 import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
 import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
 import com.google.devtools.build.lib.buildeventstream.BuildEventId;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
@@ -698,14 +699,19 @@
     }
 
     Preconditions.checkNotNull(depValueMap);
-    ConfiguredTarget configuredTarget =
-        view.createConfiguredTarget(
-            target,
-            configuration,
-            analysisEnvironment,
-            depValueMap,
-            configConditions,
-            toolchainContext);
+    ConfiguredTarget configuredTarget;
+    try {
+      configuredTarget =
+          view.createConfiguredTarget(
+              target,
+              configuration,
+              analysisEnvironment,
+              depValueMap,
+              configConditions,
+              toolchainContext);
+    } catch (ActionConflictException e) {
+      throw new ConfiguredTargetFunctionException(e);
+    }
 
     events.replayOn(env.getListener());
     if (events.hasErrors()) {
@@ -725,24 +731,34 @@
     analysisEnvironment.disable(target);
     Preconditions.checkNotNull(configuredTarget, target);
 
-    GeneratingActions generatingActions;
-    // Check for conflicting actions within this configured target (that indicates a bug in the
-    // rule implementation).
-    try {
-      generatingActions =
-          Actions.filterSharedActionsAndThrowActionConflict(
-              analysisEnvironment.getActionKeyContext(),
-              analysisEnvironment.getRegisteredActions());
-    } catch (ActionConflictException e) {
-      throw new ConfiguredTargetFunctionException(e);
+    if (configuredTarget instanceof RuleConfiguredTarget) {
+      RuleConfiguredTarget ruleConfiguredTarget = (RuleConfiguredTarget) configuredTarget;
+      return new RuleConfiguredTargetValue(
+          ruleConfiguredTarget,
+          transitivePackagesForPackageRootResolution == null
+              ? null
+              : transitivePackagesForPackageRootResolution.build(),
+          removeActionsAfterEvaluation.get());
+    } else {
+      GeneratingActions generatingActions;
+      // Check for conflicting actions within this configured target (that indicates a bug in the
+      // rule implementation).
+      try {
+        generatingActions =
+            Actions.filterSharedActionsAndThrowActionConflict(
+                analysisEnvironment.getActionKeyContext(),
+                analysisEnvironment.getRegisteredActions());
+      } catch (ActionConflictException e) {
+        throw new ConfiguredTargetFunctionException(e);
+      }
+      return new NonRuleConfiguredTargetValue(
+          configuredTarget,
+          generatingActions,
+          transitivePackagesForPackageRootResolution == null
+              ? null
+              : transitivePackagesForPackageRootResolution.build(),
+          removeActionsAfterEvaluation.get());
     }
-    return new ConfiguredTargetValue(
-        configuredTarget,
-        generatingActions,
-        transitivePackagesForPackageRootResolution == null
-            ? null
-            : transitivePackagesForPackageRootResolution.build(),
-        removeActionsAfterEvaluation.get());
   }
 
   /**
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetValue.java
index 341da8a..b527d59 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetValue.java
@@ -1,4 +1,4 @@
-// Copyright 2014 The Bazel Authors. All rights reserved.
+// Copyright 2018 The Bazel Authors. All rights reserved.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -11,109 +11,26 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
 package com.google.devtools.build.lib.skyframe;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.Action;
 import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
-import com.google.devtools.build.lib.actions.ActionLookupValue;
-import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
-import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
-import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
 import com.google.devtools.build.lib.packages.Package;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
 import com.google.devtools.build.skyframe.SkyKey;
+import com.google.devtools.build.skyframe.SkyValue;
 import java.util.List;
-import javax.annotation.Nullable;
 
-/** A configured target in the context of a Skyframe graph. */
-@AutoCodec
-@Immutable
-@ThreadSafe
-@VisibleForTesting
-public final class ConfiguredTargetValue extends ActionLookupValue {
-  // These variables are only non-final because they may be clear()ed to save memory.
-  // configuredTarget is null only after it is cleared.
-  @Nullable private ConfiguredTarget configuredTarget;
-
-  // May be null either after clearing or because transitive packages are not tracked.
-  @Nullable private NestedSet<Package> transitivePackagesForPackageRootResolution;
-
-  @AutoCodec.Instantiator
-  @VisibleForSerialization
-  ConfiguredTargetValue(
-      List<ActionAnalysisMetadata> actions,
-      ImmutableMap<Artifact, Integer> generatingActionIndex,
-      ConfiguredTarget configuredTarget,
-      NestedSet<Package> transitivePackagesForPackageRootResolution) {
-    super(actions, generatingActionIndex);
-    this.configuredTarget = configuredTarget;
-    this.transitivePackagesForPackageRootResolution = transitivePackagesForPackageRootResolution;
-  }
-
-  ConfiguredTargetValue(
-      ConfiguredTarget configuredTarget,
-      GeneratingActions generatingActions,
-      @Nullable NestedSet<Package> transitivePackagesForPackageRootResolution,
-      boolean removeActionsAfterEvaluation) {
-    super(generatingActions, removeActionsAfterEvaluation);
-    this.configuredTarget = Preconditions.checkNotNull(configuredTarget, generatingActions);
-    this.transitivePackagesForPackageRootResolution = transitivePackagesForPackageRootResolution;
-  }
-
-  @VisibleForTesting
-  public ConfiguredTarget getConfiguredTarget() {
-    Preconditions.checkNotNull(configuredTarget);
-    return configuredTarget;
-  }
-
-  @VisibleForTesting
-  public List<ActionAnalysisMetadata> getActions() {
-    Preconditions.checkNotNull(configuredTarget, this);
-    return actions;
-  }
-
-  /**
-   * Returns the set of packages transitively loaded by this value. Must only be used for
-   * constructing the package -> source root map needed for some builds. If the caller has not
-   * specified that this map needs to be constructed (via the constructor argument in {@link
-   * ConfiguredTargetFunction#ConfiguredTargetFunction}), calling this will crash.
-   */
-  public NestedSet<Package> getTransitivePackagesForPackageRootResolution() {
-    return Preconditions.checkNotNull(transitivePackagesForPackageRootResolution);
-  }
-
-  /**
-   * Clears configured target data from this value, leaving only the artifact->generating action
-   * map.
-   *
-   * <p>Should only be used when user specifies --discard_analysis_cache. Must be called at most
-   * once per value, after which {@link #getConfiguredTarget} and {@link #getActions} cannot be
-   * called.
-   *
-   * @param clearEverything if true, clear the {@link #configuredTarget}. If not, only the {@link
-   *     #transitivePackagesForPackageRootResolution} field is cleared. Top-level targets need their
-   *     {@link #configuredTarget} preserved, so should pass false here.
-   */
-  public void clear(boolean clearEverything) {
-    Preconditions.checkNotNull(configuredTarget);
-    Preconditions.checkNotNull(transitivePackagesForPackageRootResolution);
-    if (clearEverything) {
-      configuredTarget = null;
-    }
-    transitivePackagesForPackageRootResolution = null;
-  }
-
-  @VisibleForTesting
-  public static SkyKey key(Label label, BuildConfiguration configuration) {
+/**
+ * A {@link SkyValue} for a {@link ConfiguredTarget}.
+ */
+public interface ConfiguredTargetValue extends SkyValue {
+  static SkyKey key(Label label, BuildConfiguration configuration) {
     return ConfiguredTargetKey.of(label, configuration);
   }
 
@@ -126,17 +43,35 @@
   }
 
   /**
-   * Returns a label of ConfiguredTargetValue.
+   * Returns the configured target for this value.
    */
-  @ThreadSafe
-  static Label extractLabel(SkyKey value) {
-    Object valueName = value.argument();
-    Preconditions.checkState(valueName instanceof ConfiguredTargetKey, valueName);
-    return ((ConfiguredTargetKey) valueName).getLabel();
-  }
+  ConfiguredTarget getConfiguredTarget();
 
-  @Override
-  public String toString() {
-    return getStringHelper().add("configuredTarget", configuredTarget).toString();
-  }
+  /**
+   * Returns the set of packages transitively loaded by this value. Must only be used for
+   * constructing the package -> source root map needed for some builds. If the caller has not
+   * specified that this map needs to be constructed (via the constructor argument in {@link
+   * ConfiguredTargetFunction#ConfiguredTargetFunction}), calling this will crash.
+   */
+  NestedSet<Package> getTransitivePackagesForPackageRootResolution();
+
+  /**
+   * Returns the actions registered by the configured target for this value.
+   */
+  List<ActionAnalysisMetadata> getActions();
+
+  /**
+   * Returns the number of {@link Action} objects present in this value.
+   */
+  int getNumActions();
+
+  /**
+   * Clears configured target data from this value, leaving only the artifact->generating action
+   * map.
+   *
+   * <p>Should only be used when user specifies --discard_analysis_cache. Must be called at most
+   * once per value, after which {@link #getConfiguredTarget} and {@link #getActions} cannot be
+   * called.
+   */
+  void clear(boolean clearEverything);
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/CoverageReportValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/CoverageReportValue.java
index e752285..ce7745a 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/CoverageReportValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/CoverageReportValue.java
@@ -14,15 +14,15 @@
 
 package com.google.devtools.build.lib.skyframe;
 
-import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.skyframe.SkyFunctionName;
 
 /**
  * A SkyValue to store the coverage report Action and Artifacts.
  */
-public class CoverageReportValue extends ActionLookupValue {
+public class CoverageReportValue extends BasicActionLookupValue {
 
   // There should only ever be one CoverageReportValue value in the graph.
   @AutoCodec public static final CoverageReportKey COVERAGE_REPORT_KEY = new CoverageReportKey();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/NonRuleConfiguredTargetValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/NonRuleConfiguredTargetValue.java
new file mode 100644
index 0000000..b36318b
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/NonRuleConfiguredTargetValue.java
@@ -0,0 +1,117 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.Actions.GeneratingActions;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
+import com.google.devtools.build.skyframe.SkyKey;
+import java.util.ArrayList;
+import javax.annotation.Nullable;
+
+/**
+ * A configured target in the context of a Skyframe graph.
+ */
+@Immutable
+@ThreadSafe
+@AutoCodec
+@VisibleForTesting
+public final class NonRuleConfiguredTargetValue
+    extends BasicActionLookupValue implements ConfiguredTargetValue {
+
+  // These variables are only non-final because they may be clear()ed to save memory.
+  // configuredTarget is null only after it is cleared.
+  @Nullable private ConfiguredTarget configuredTarget;
+
+  // May be null either after clearing or because transitive packages are not tracked.
+  @Nullable private NestedSet<Package> transitivePackagesForPackageRootResolution;
+
+  @AutoCodec.Instantiator
+  @VisibleForSerialization
+  NonRuleConfiguredTargetValue(
+      ArrayList<ActionAnalysisMetadata> actions,
+      ImmutableMap<Artifact, Integer> generatingActionIndex,
+      ConfiguredTarget configuredTarget,
+      NestedSet<Package> transitivePackagesForPackageRootResolution) {
+    super(actions, generatingActionIndex, false);
+    this.configuredTarget = configuredTarget;
+    this.transitivePackagesForPackageRootResolution = transitivePackagesForPackageRootResolution;
+  }
+
+  NonRuleConfiguredTargetValue(
+      ConfiguredTarget configuredTarget,
+      GeneratingActions generatingActions,
+      @Nullable NestedSet<Package> transitivePackagesForPackageRootResolution,
+      boolean removeActionsAfterEvaluation) {
+    super(generatingActions, removeActionsAfterEvaluation);
+    this.configuredTarget = Preconditions.checkNotNull(configuredTarget, generatingActions);
+    this.transitivePackagesForPackageRootResolution = transitivePackagesForPackageRootResolution;
+  }
+
+  @VisibleForTesting
+  @Override
+  public ConfiguredTarget getConfiguredTarget() {
+    Preconditions.checkNotNull(configuredTarget);
+    return configuredTarget;
+  }
+
+  @VisibleForTesting
+  @Override
+  public ArrayList<ActionAnalysisMetadata> getActions() {
+    Preconditions.checkNotNull(configuredTarget, this);
+    return actions;
+  }
+
+  @Override
+  public NestedSet<Package> getTransitivePackagesForPackageRootResolution() {
+    return Preconditions.checkNotNull(transitivePackagesForPackageRootResolution);
+  }
+
+  @Override
+  public void clear(boolean clearEverything) {
+    Preconditions.checkNotNull(configuredTarget);
+    Preconditions.checkNotNull(transitivePackagesForPackageRootResolution);
+    if (clearEverything) {
+      configuredTarget = null;
+    }
+    transitivePackagesForPackageRootResolution = null;
+  }
+
+  /**
+   * Returns a label of NonRuleConfiguredTargetValue.
+   */
+  @ThreadSafe
+  static Label extractLabel(SkyKey value) {
+    Object valueName = value.argument();
+    Preconditions.checkState(valueName instanceof ConfiguredTargetKey, valueName);
+    return ((ConfiguredTargetKey) valueName).getLabel();
+  }
+
+  @Override
+  public String toString() {
+    return getStringHelper().add("configuredTarget", configuredTarget).toString();
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RuleConfiguredTargetValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/RuleConfiguredTargetValue.java
new file mode 100644
index 0000000..8eaa016
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RuleConfiguredTargetValue.java
@@ -0,0 +1,109 @@
+// Copyright 2014 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skyframe;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.actions.ActionLookupValue;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
+import com.google.devtools.build.lib.packages.Package;
+import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
+import java.util.ArrayList;
+import javax.annotation.Nullable;
+
+/**
+ * A configured target in the context of a Skyframe graph.
+ */
+@Immutable
+@ThreadSafe
+@AutoCodec
+@VisibleForTesting
+public final class RuleConfiguredTargetValue extends ActionLookupValue
+    implements ConfiguredTargetValue {
+
+  // This variable is non-final because it may be clear()ed to save memory. It is null only after
+  // clear(true) is called.
+  @Nullable private RuleConfiguredTarget configuredTarget;
+  private final ArrayList<ActionAnalysisMetadata> actions;
+  private final ImmutableMap<Artifact, Integer> generatingActionIndex;
+
+  // May be null either after clearing or because transitive packages are not tracked.
+  @Nullable private NestedSet<Package> transitivePackagesForPackageRootResolution;
+
+  @AutoCodec.Instantiator
+  RuleConfiguredTargetValue(
+      RuleConfiguredTarget configuredTarget,
+      @Nullable NestedSet<Package> transitivePackagesForPackageRootResolution) {
+    this(configuredTarget, transitivePackagesForPackageRootResolution, false);
+  }
+
+  RuleConfiguredTargetValue(
+      RuleConfiguredTarget configuredTarget,
+      @Nullable NestedSet<Package> transitivePackagesForPackageRootResolution,
+      boolean removeActionsAfterEvaluation) {
+    super(removeActionsAfterEvaluation);
+    this.configuredTarget = Preconditions.checkNotNull(configuredTarget);
+    this.transitivePackagesForPackageRootResolution = transitivePackagesForPackageRootResolution;
+    // These are specifically *not* copied to save memory.
+    this.actions = configuredTarget.getActions();
+    this.generatingActionIndex = configuredTarget.getGeneratingActionIndex();
+    // If actions are removed after evaluation, the configured target's account of actions is
+    // incomplete and may be partially nulled-out. Thus, access of these actions via skylark should
+    // be disabled.
+    // TODO(b/70636031): Deprecate and remove this optimization.
+    if (removeActionsAfterEvaluation) {
+      configuredTarget.disableAcccesibleActions();
+    }
+  }
+
+  @VisibleForTesting
+  @Override
+  public ConfiguredTarget getConfiguredTarget() {
+    Preconditions.checkNotNull(configuredTarget);
+    return configuredTarget;
+  }
+
+  @VisibleForTesting
+  @Override
+  public ArrayList<ActionAnalysisMetadata> getActions() {
+    return actions;
+  }
+
+  @Override
+  protected ImmutableMap<Artifact, Integer> getGeneratingActionIndex() {
+    return generatingActionIndex;
+  }
+
+  @Override
+  public NestedSet<Package> getTransitivePackagesForPackageRootResolution() {
+    return Preconditions.checkNotNull(transitivePackagesForPackageRootResolution);
+  }
+
+  @Override
+  public void clear(boolean clearEverything) {
+    Preconditions.checkNotNull(configuredTarget);
+    Preconditions.checkNotNull(transitivePackagesForPackageRootResolution);
+    if (clearEverything) {
+      configuredTarget = null;
+    }
+    transitivePackagesForPackageRootResolution = null;
+  }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
index 8d9c151..5d9cde9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
@@ -30,7 +30,6 @@
 import com.google.devtools.build.lib.actions.ArtifactFactory;
 import com.google.devtools.build.lib.actions.ArtifactOwner;
 import com.google.devtools.build.lib.actions.ArtifactPrefixConflictException;
-import com.google.devtools.build.lib.actions.MutableActionGraph;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.PackageRoots;
 import com.google.devtools.build.lib.analysis.AnalysisFailureEvent;
@@ -270,7 +269,7 @@
         ConflictException ex = bad.getValue();
         try {
           ex.rethrowTyped();
-        } catch (MutableActionGraph.ActionConflictException ace) {
+        } catch (ActionConflictException ace) {
           ace.reportTo(eventHandler);
           String errorMsg = "Analysis of target '" + bad.getKey().getOwner().getLabel()
               + "' failed; build aborted";
@@ -294,7 +293,7 @@
       if (topLevel.argument() instanceof ConfiguredTargetKey) {
         errorMsg =
             "Analysis of target '"
-                + ConfiguredTargetValue.extractLabel(topLevel)
+                + NonRuleConfiguredTargetValue.extractLabel(topLevel)
                 + "' failed; build aborted";
       } else if (topLevel.argument() instanceof AspectValueKey) {
         AspectValueKey aspectKey = (AspectValueKey) topLevel.argument();
@@ -313,7 +312,7 @@
     }
 
     boolean hasLoadingError = false;
-    // --keep_going : We notify the error and return a ConfiguredTargetValue
+    // --keep_going : We notify the error and return a NonRuleConfiguredTargetValue
     for (Map.Entry<SkyKey, ErrorInfo> errorEntry : result.errorMap().entrySet()) {
       // Only handle errors of configured targets, not errors of top-level aspects.
       // TODO(ulfjack): this is quadratic - if there are a lot of CTs, this could be rather slow.
@@ -363,7 +362,7 @@
       ConflictException ex = bad.getValue();
       try {
         ex.rethrowTyped();
-      } catch (MutableActionGraph.ActionConflictException ace) {
+      } catch (ActionConflictException ace) {
         ace.reportTo(eventHandler);
         eventHandler
             .handle(Event.warn("errors encountered while analyzing target '"
@@ -508,7 +507,7 @@
       OrderedSetMultimap<Attribute, ConfiguredTargetAndTarget> prerequisiteMap,
       ImmutableMap<Label, ConfigMatchingProvider> configConditions,
       @Nullable ToolchainContext toolchainContext)
-      throws InterruptedException {
+      throws InterruptedException, ActionConflictException {
     Preconditions.checkState(enableAnalysis,
         "Already in execution phase %s %s", target, configuration);
     Preconditions.checkNotNull(analysisEnvironment);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceStatusValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceStatusValue.java
index 0bbff1c..0a748f9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceStatusValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/WorkspaceStatusValue.java
@@ -13,8 +13,8 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
-import com.google.devtools.build.lib.actions.ActionLookupValue;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.analysis.WorkspaceStatusAction;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.skyframe.SkyFunctionName;
@@ -26,7 +26,7 @@
  */
 // TODO(bazel-team): This seems to be superfluous now, but it cannot be removed without making
 // PrecomputedValue public instead of package-private
-public class WorkspaceStatusValue extends ActionLookupValue {
+public class WorkspaceStatusValue extends BasicActionLookupValue {
   private final Artifact stableArtifact;
   private final Artifact volatileArtifact;
 
diff --git a/src/test/java/com/google/devtools/build/docgen/BUILD b/src/test/java/com/google/devtools/build/docgen/BUILD
index 4f302cc..2d3ffdf 100644
--- a/src/test/java/com/google/devtools/build/docgen/BUILD
+++ b/src/test/java/com/google/devtools/build/docgen/BUILD
@@ -64,6 +64,7 @@
     deps = [
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:packages-internal",
+        "//src/main/java/com/google/devtools/build/lib/actions",
     ],
 )
 
diff --git a/src/test/java/com/google/devtools/build/docgen/testutil/TestData.java b/src/test/java/com/google/devtools/build/docgen/testutil/TestData.java
index a8f136a..b3bf347 100644
--- a/src/test/java/com/google/devtools/build/docgen/testutil/TestData.java
+++ b/src/test/java/com/google/devtools/build/docgen/testutil/TestData.java
@@ -16,6 +16,7 @@
 import static com.google.devtools.build.lib.packages.Attribute.attr;
 import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
 import com.google.devtools.build.lib.analysis.RuleContext;
@@ -70,7 +71,8 @@
 
   public static class DummyRuleFactory implements RuleConfiguredTargetFactory {
     @Override
-    public ConfiguredTarget create(RuleContext ruleContext) {
+    public ConfiguredTarget create(RuleContext ruleContext)
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       throw new IllegalStateException();
     }
   }
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 99d4335..462d3f2 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -724,6 +724,7 @@
         "//src/main/java/com/google/devtools/build/lib:bazel-rules",
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:packages",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/vfs",
     ],
 )
@@ -860,6 +861,7 @@
         "//src/main/java/com/google/devtools/build/lib:packages",
         "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
         "//src/main/java/com/google/devtools/build/lib:util",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/skyframe/serialization",
         "//src/main/java/com/google/devtools/build/lib/skyframe/serialization/testutils",
         "//src/main/java/com/google/devtools/build/lib/vfs",
diff --git a/src/test/java/com/google/devtools/build/lib/actions/ActionLookupValueTest.java b/src/test/java/com/google/devtools/build/lib/actions/BasicActionLookupValueTest.java
similarity index 94%
rename from src/test/java/com/google/devtools/build/lib/actions/ActionLookupValueTest.java
rename to src/test/java/com/google/devtools/build/lib/actions/BasicActionLookupValueTest.java
index f6c5961..a356cb5 100644
--- a/src/test/java/com/google/devtools/build/lib/actions/ActionLookupValueTest.java
+++ b/src/test/java/com/google/devtools/build/lib/actions/BasicActionLookupValueTest.java
@@ -30,9 +30,9 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/** Basic tests for {@link ActionLookupValue}. */
+/** Basic tests for {@link BasicActionLookupValue}. */
 @RunWith(JUnit4.class)
-public class ActionLookupValueTest {
+public class BasicActionLookupValueTest {
 
   private FileSystem fs;
   private final ActionKeyContext actionKeyContext = new ActionKeyContext();
@@ -48,7 +48,7 @@
     Artifact artifact = mock(Artifact.class);
     when(action.getOutputs()).thenReturn(ImmutableSet.of(artifact));
     when(action.canRemoveAfterExecution()).thenReturn(true);
-    ActionLookupValue underTest = new ActionLookupValue(action, false);
+    ActionLookupValue underTest = new BasicActionLookupValue(action, false);
     assertThat(underTest.getGeneratingActionIndex(artifact)).isEqualTo(0);
     assertThat(underTest.getAction(0)).isSameAs(action);
     underTest.actionEvaluated(0, action);
@@ -69,7 +69,7 @@
     when(persistentAction.getOutputs()).thenReturn(ImmutableSet.of(persistentOutput));
     when(persistentAction.canRemoveAfterExecution()).thenReturn(false);
     ActionLookupValue underTest =
-        new ActionLookupValue(
+        new BasicActionLookupValue(
             Actions.filterSharedActionsAndThrowActionConflict(
                 actionKeyContext, ImmutableList.of(normalAction, persistentAction)),
             true);
@@ -81,7 +81,7 @@
     try {
       underTest.getAction(0);
       fail();
-    } catch (NullPointerException e) {
+    } catch (IllegalStateException e) {
       // Expected.
     }
     assertThat(underTest.getGeneratingActionIndex(persistentOutput)).isEqualTo(1);
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/select/AggregatingAttributeMapperTest.java b/src/test/java/com/google/devtools/build/lib/analysis/select/AggregatingAttributeMapperTest.java
index 2eda4e0..a8f9126 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/select/AggregatingAttributeMapperTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/select/AggregatingAttributeMapperTest.java
@@ -21,6 +21,7 @@
 import com.google.common.base.Verify;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -272,7 +273,8 @@
     }
 
     @Override
-    public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+    public ConfiguredTarget create(RuleContext ruleContext)
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       throw new UnsupportedOperationException();
     }
   }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleDefaults.java b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleDefaults.java
index 1bba9b1..98f652c 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleDefaults.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/MockRuleDefaults.java
@@ -22,6 +22,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -78,7 +79,8 @@
    * */
   public static class DefaultConfiguredTargetFactory implements RuleConfiguredTargetFactory {
     @Override
-    public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+    public ConfiguredTarget create(RuleContext ruleContext)
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       NestedSet<Artifact> filesToBuild =
           NestedSetBuilder.wrap(Order.STABLE_ORDER, ruleContext.getOutputArtifacts());
       for (Artifact artifact : ruleContext.getOutputArtifacts()) {
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java b/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
index dcea00a..1f27af4 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/util/TestAspects.java
@@ -24,6 +24,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredAspect;
 import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -150,7 +151,8 @@
    */
   public static class DummyRuleFactory implements RuleConfiguredTargetFactory {
     @Override
-    public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+    public ConfiguredTarget create(RuleContext ruleContext)
+        throws InterruptedException, RuleErrorException, ActionConflictException {
 
       RuleConfiguredTargetBuilder builder =
           new RuleConfiguredTargetBuilder(ruleContext)
@@ -173,7 +175,8 @@
    */
   public static class DummyRuleFactory2 implements RuleConfiguredTargetFactory {
     @Override
-    public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+    public ConfiguredTarget create(RuleContext ruleContext)
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       return new RuleConfiguredTargetBuilder(ruleContext)
               .addProvider(
                   new RuleInfo(collectAspectData("rule " + ruleContext.getLabel(), ruleContext)))
@@ -192,7 +195,8 @@
    */
   public static class MultiAspectRuleFactory implements RuleConfiguredTargetFactory {
     @Override
-    public ConfiguredTarget create(RuleContext ruleContext) throws InterruptedException {
+    public ConfiguredTarget create(RuleContext ruleContext)
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       TransitiveInfoCollection fooAttribute = ruleContext.getPrerequisite("foo", Mode.DONT_CHECK);
       TransitiveInfoCollection barAttribute = ruleContext.getPrerequisite("bar", Mode.DONT_CHECK);
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/BUILD b/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/BUILD
index 042b4bb..97cb185 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/BUILD
@@ -20,6 +20,7 @@
         "//src/main/java/com/google/devtools/build/lib:build-base",
         "//src/main/java/com/google/devtools/build/lib:packages-internal",
         "//src/main/java/com/google/devtools/build/lib:util",
+        "//src/main/java/com/google/devtools/build/lib/actions",
         "//src/main/java/com/google/devtools/build/lib/analysis/whitelisting",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/collect",
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/WhitelistDummyRule.java b/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/WhitelistDummyRule.java
index 94563f6..6e4ce84 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/WhitelistDummyRule.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/whitelisting/WhitelistDummyRule.java
@@ -14,6 +14,7 @@
 
 package com.google.devtools.build.lib.analysis.whitelisting;
 
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -39,7 +40,7 @@
   public static class RuleFactory implements RuleConfiguredTargetFactory {
     @Override
     public ConfiguredTarget create(RuleContext ruleContext)
-        throws InterruptedException, RuleErrorException {
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       if (!Whitelist.isAvailable(ruleContext, "dummy")) {
         ruleContext.ruleError("Dummy is not available.");
       }
diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassBuilderTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassBuilderTest.java
index b25436d..cbfdbfb 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassBuilderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassBuilderTest.java
@@ -23,6 +23,7 @@
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
 import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
@@ -36,11 +37,12 @@
  */
 @RunWith(JUnit4.class)
 public class RuleClassBuilderTest extends PackageLoadingTestCase {
-  private static final RuleClass.ConfiguredTargetFactory<Object, Object>
+  private static final RuleClass.ConfiguredTargetFactory<Object, Object, Exception>
       DUMMY_CONFIGURED_TARGET_FACTORY =
-          new RuleClass.ConfiguredTargetFactory<Object, Object>() {
+          new RuleClass.ConfiguredTargetFactory<Object, Object, Exception>() {
             @Override
-            public Object create(Object ruleContext) throws InterruptedException {
+            public Object create(Object ruleContext)
+                throws InterruptedException, RuleErrorException, ActionConflictException {
               throw new IllegalStateException();
             }
           };
diff --git a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
index 95c243d..cf324c1 100644
--- a/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
+++ b/src/test/java/com/google/devtools/build/lib/packages/RuleClassTest.java
@@ -35,6 +35,7 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
@@ -76,13 +77,15 @@
  */
 @RunWith(JUnit4.class)
 public class RuleClassTest extends PackageLoadingTestCase {
-  private static final RuleClass.ConfiguredTargetFactory<Object, Object>
-      DUMMY_CONFIGURED_TARGET_FACTORY = new RuleClass.ConfiguredTargetFactory<Object, Object>() {
-        @Override
-        public Object create(Object ruleContext) throws InterruptedException {
-          throw new IllegalStateException();
-        }
-  };
+  private static final RuleClass.ConfiguredTargetFactory<Object, Object, Exception>
+      DUMMY_CONFIGURED_TARGET_FACTORY =
+          new RuleClass.ConfiguredTargetFactory<Object, Object, Exception>() {
+            @Override
+            public Object create(Object ruleContext)
+                throws InterruptedException, RuleErrorException, ActionConflictException {
+              throw new IllegalStateException();
+            }
+          };
 
   private static final class DummyFragment extends BuildConfiguration.Fragment {
 
@@ -845,7 +848,7 @@
       boolean outputsDefaultExecutable,
       ImplicitOutputsFunction implicitOutputsFunction,
       RuleTransitionFactory transitionFactory,
-      ConfiguredTargetFactory<?, ?> configuredTargetFactory,
+      ConfiguredTargetFactory<?, ?, ?> configuredTargetFactory,
       PredicateWithMessage<Rule> validityPredicate,
       Predicate<String> preferredDependencyPredicate,
       AdvertisedProviderSet advertisedProviders,
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagSetterRule.java b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagSetterRule.java
index e4266d5..4b466ae 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagSetterRule.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagSetterRule.java
@@ -22,6 +22,7 @@
 
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
@@ -75,7 +76,7 @@
 
   @Override
   public ConfiguredTarget create(RuleContext ruleContext)
-      throws InterruptedException, RuleErrorException {
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     TransitiveInfoCollection exportedFlag =
         ruleContext.getPrerequisite("exports_flag", Mode.TARGET);
     ConfigFeatureFlagProvider exportedFlagProvider =
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java
index ba1a3c2..9703fb4 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ActionTemplateExpansionFunctionTest.java
@@ -219,7 +219,7 @@
 
   private static ConfiguredTargetValue createConfiguredTargetValue(
       ActionTemplate<?> actionTemplate) {
-    return new ConfiguredTargetValue(
+    return new NonRuleConfiguredTargetValue(
         Mockito.mock(ConfiguredTarget.class),
         Actions.GeneratingActions.fromSingleAction(actionTemplate),
         NestedSetBuilder.<Package>stableOrder().build(),
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
index 8a4f3af..2fa5749 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
@@ -32,6 +32,7 @@
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.actions.MissingInputFileException;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
@@ -324,7 +325,7 @@
       differencer.inject(
           ImmutableMap.of(
               ALL_OWNER,
-              new ActionLookupValue(
+              new BasicActionLookupValue(
                   Actions.filterSharedActionsAndThrowActionConflict(
                       actionKeyContext, ImmutableList.copyOf(actions)),
                   false)));
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
index 40c74d0..3348527 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TimestampBuilderTestCase.java
@@ -41,6 +41,7 @@
 import com.google.devtools.build.lib.actions.Actions;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.actions.BuildFailedException;
 import com.google.devtools.build.lib.actions.Executor;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
@@ -242,7 +243,7 @@
           differencer.inject(
               ImmutableMap.of(
                   ACTION_LOOKUP_KEY,
-                  new ActionLookupValue(
+                  new BasicActionLookupValue(
                       Actions.filterSharedActionsAndThrowActionConflict(
                           actionKeyContext, ImmutableList.copyOf(actions)),
                       false)));
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunctionTest.java
index 702929b..ae35626 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ToolchainResolutionFunctionTest.java
@@ -46,7 +46,7 @@
 
   private static ConfiguredTargetValue createConfiguredTargetValue(
       ConfiguredTarget configuredTarget) {
-    return new ConfiguredTargetValue(
+    return new NonRuleConfiguredTargetValue(
         configuredTarget,
         GeneratingActions.EMPTY,
         NestedSetBuilder.emptySet(Order.STABLE_ORDER),
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
index 7a804e4..47ca57b 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TreeArtifactMetadataTest.java
@@ -33,6 +33,7 @@
 import com.google.devtools.build.lib.actions.Artifact.SpecialArtifactType;
 import com.google.devtools.build.lib.actions.Artifact.TreeFileArtifact;
 import com.google.devtools.build.lib.actions.ArtifactRoot;
+import com.google.devtools.build.lib.actions.BasicActionLookupValue;
 import com.google.devtools.build.lib.actions.MissingInputFileException;
 import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.actions.cache.DigestUtils;
@@ -228,7 +229,7 @@
       differencer.inject(
           ImmutableMap.of(
               ALL_OWNER,
-              new ActionLookupValue(
+              new BasicActionLookupValue(
                   Actions.filterSharedActionsAndThrowActionConflict(
                       actionKeyContext, ImmutableList.copyOf(actions)),
                   false)));
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkActionProviderTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkActionProviderTest.java
new file mode 100644
index 0000000..0adabd1
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkActionProviderTest.java
@@ -0,0 +1,107 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.skylark;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
+import com.google.devtools.build.lib.analysis.BuildView.AnalysisResult;
+import com.google.devtools.build.lib.analysis.ConfiguredAspect;
+import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.packages.SkylarkProvider.SkylarkKey;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Tests for the Skylark-accessible actions provider on rule configured targets. */
+@RunWith(JUnit4.class)
+public class SkylarkActionProviderTest extends AnalysisTestCase {
+
+  @Test
+  public void aspectGetsActionProviderForNativeRule() throws Exception {
+    scratch.file(
+        "test/aspect.bzl",
+        "foo = provider()",
+        "def _impl(target, ctx):",
+        "   return [foo(actions = target.actions)]",
+        "MyAspect = aspect(implementation=_impl)");
+    scratch.file(
+        "test/BUILD",
+        "genrule(",
+        "   name = 'xxx',",
+        "   cmd = 'echo \"hello\" > $@',",
+        "   outs = ['mygen.out']",
+        ")");
+
+    AnalysisResult analysisResult =
+        update(ImmutableList.of("test/aspect.bzl%MyAspect"), "//test:xxx");
+
+    ConfiguredAspect configuredAspect =
+        Iterables.getOnlyElement(analysisResult.getAspects()).getConfiguredAspect();
+
+    SkylarkKey fooKey = new SkylarkKey(Label.parseAbsolute("//test:aspect.bzl"), "foo");
+
+    assertThat(configuredAspect.get(fooKey).getValue("actions")).isNotNull();
+    @SuppressWarnings("unchecked")
+    SkylarkList<ActionAnalysisMetadata> actions =
+        (SkylarkList<ActionAnalysisMetadata>) configuredAspect.get(fooKey).getValue("actions");
+    assertThat(actions).isNotEmpty();
+
+    ActionAnalysisMetadata action = actions.get(0);
+    assertThat(action.getMnemonic()).isEqualTo("Genrule");
+  }
+
+  @Test
+  public void aspectGetsActionProviderForSkylarkRule() throws Exception {
+    scratch.file(
+        "test/aspect.bzl",
+        "foo = provider()",
+        "def _impl(target, ctx):",
+        "   return [foo(actions = target.actions)]",
+        "MyAspect = aspect(implementation=_impl)");
+    scratch.file(
+        "test/rule.bzl",
+        "def impl(ctx):",
+        "  output_file0 = ctx.new_file('myfile0')",
+        "  output_file1 = ctx.new_file('myfile1')",
+        "  ctx.action(outputs=[output_file0], command='fakecmd0', mnemonic='MyAction0')",
+        "  ctx.action(outputs=[output_file1], command='fakecmd1', mnemonic='MyAction1')",
+        "  return None",
+        "my_rule = rule(impl)");
+    scratch.file(
+        "test/BUILD", "load('//test:rule.bzl', 'my_rule')", "my_rule(", "   name = 'xxx',", ")");
+
+    AnalysisResult analysisResult =
+        update(ImmutableList.of("test/aspect.bzl%MyAspect"), "//test:xxx");
+
+    ConfiguredAspect configuredAspect =
+        Iterables.getOnlyElement(analysisResult.getAspects()).getConfiguredAspect();
+
+    SkylarkKey fooKey = new SkylarkKey(Label.parseAbsolute("//test:aspect.bzl"), "foo");
+
+    assertThat(configuredAspect.get(fooKey).getValue("actions")).isNotNull();
+    @SuppressWarnings("unchecked")
+    SkylarkList<ActionAnalysisMetadata> actions =
+        (SkylarkList<ActionAnalysisMetadata>) configuredAspect.get(fooKey).getValue("actions");
+    assertThat(actions).hasSize(2);
+
+    assertThat(actions.stream().map(action -> action.getMnemonic()).collect(Collectors.toList()))
+        .containsExactly("MyAction0", "MyAction1");
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkDefinedAspectsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkDefinedAspectsTest.java
index d4ad66d..10acb87 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkDefinedAspectsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkDefinedAspectsTest.java
@@ -358,6 +358,7 @@
     Info names = target.get(providerKey);
     assertThat((Iterable<?>) names.getValue("dir"))
         .containsExactly(
+            "actions",
             "aspect_provider",
             "data_runfiles",
             "default_runfiles",
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
index 83d7e93..9ad90de 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -433,7 +433,7 @@
         "unexpected keyword 'providers' in call to string", "attr.string(providers = ['a'])");
   }
 
-  private static final RuleClass.ConfiguredTargetFactory<Object, Object>
+  private static final RuleClass.ConfiguredTargetFactory<Object, Object, Exception>
       DUMMY_CONFIGURED_TARGET_FACTORY =
           ruleContext -> {
             throw new IllegalStateException();
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java b/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java
index 72e8eb9..c9c5083 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/TestRuleClassProvider.java
@@ -22,6 +22,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.BaseRuleClasses;
 import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
@@ -113,7 +114,7 @@
 
     @Override
     public ConfiguredTarget create(RuleContext ruleContext)
-        throws InterruptedException, RuleErrorException {
+        throws InterruptedException, RuleErrorException, ActionConflictException {
       Map<String, String> variables = ruleContext.attributes().get("variables", Type.STRING_DICT);
       return new RuleConfiguredTargetBuilder(ruleContext)
           .setFilesToBuild(NestedSetBuilder.emptySet(Order.STABLE_ORDER))
diff --git a/src/test/java/com/google/devtools/build/lib/testutil/UnknownRuleConfiguredTarget.java b/src/test/java/com/google/devtools/build/lib/testutil/UnknownRuleConfiguredTarget.java
index ce38e2d..f0cfb95 100644
--- a/src/test/java/com/google/devtools/build/lib/testutil/UnknownRuleConfiguredTarget.java
+++ b/src/test/java/com/google/devtools/build/lib/testutil/UnknownRuleConfiguredTarget.java
@@ -17,6 +17,7 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.actions.Artifact;
 import com.google.devtools.build.lib.actions.FailAction;
+import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException;
 import com.google.devtools.build.lib.analysis.ConfiguredTarget;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
 import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
@@ -34,7 +35,8 @@
 public class UnknownRuleConfiguredTarget implements RuleConfiguredTargetFactory {
 
   @Override
-  public ConfiguredTarget create(RuleContext context)  {
+  public ConfiguredTarget create(RuleContext context)
+      throws InterruptedException, RuleErrorException, ActionConflictException {
     // TODO(bazel-team): (2009) why isn't this an error?  It would stop the build more promptly...
     context.ruleWarning("cannot build " + context.getRule().getRuleClass() + " rules");