diff --git a/lib/customisation.nix b/lib/customisation.nix
index 483ef6fd4866..fb78335ea1c2 100644
--- a/lib/customisation.nix
+++ b/lib/customisation.nix
@@ -36,7 +36,7 @@ rec {
   overrideDerivation = drv: f:
     let
       newDrv = derivation (drv.drvAttrs // (f drv));
-    in addPassthru newDrv (
+    in lib.flip (extendDerivation true) newDrv (
       { meta = drv.meta or {};
         passthru = if drv ? passthru then drv.passthru else {};
       }
@@ -131,8 +131,8 @@ rec {
 
 
   /* Add attributes to each output of a derivation without changing
-     the derivation itself. */
-  addPassthru = drv: passthru:
+     the derivation itself and check a given condition when evaluating. */
+  extendDerivation = condition: passthru: drv:
     let
       outputs = drv.outputs or [ "out" ];
 
@@ -142,13 +142,23 @@ rec {
       outputToAttrListElement = outputName:
         { name = outputName;
           value = commonAttrs // {
-            inherit (drv.${outputName}) outPath drvPath type outputName;
+            inherit (drv.${outputName}) type outputName;
+            drvPath = assert condition; drv.${outputName}.drvPath;
+            outPath = assert condition; drv.${outputName}.outPath;
           };
         };
 
       outputsList = map outputToAttrListElement outputs;
-  in commonAttrs // { outputUnspecified = true; };
+    in commonAttrs // {
+      outputUnspecified = true;
+      drvPath = assert condition; drv.drvPath;
+      outPath = assert condition; drv.outPath;
+    };
 
+  /* Add attributes to each output of a derivation without changing
+     the derivation itself. */
+  addPassthru = lib.warn "`addPassthru` is deprecated, replace with `extendDerivation true`"
+                         (extendDerivation true);
 
   /* Strip a derivation of all non-essential attributes, returning
      only those needed by hydra-eval-jobs. Also strictly evaluate the
diff --git a/lib/default.nix b/lib/default.nix
index 03a902945a3b..6d2a95e559c8 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -87,7 +87,8 @@ let
     inherit (stringsWithDeps) textClosureList textClosureMap
       noDepEntry fullDepEntry packEntry stringAfter;
     inherit (customisation) overrideDerivation makeOverridable
-      callPackageWith callPackagesWith addPassthru hydraJob makeScope;
+      callPackageWith callPackagesWith extendDerivation addPassthru
+      hydraJob makeScope;
     inherit (meta) addMetaAttrs dontDistribute setName updateName
       appendToName mapDerivationAttrset lowPrio lowPrioSet hiPrio
       hiPrioSet;
diff --git a/nixos/doc/manual/release-notes/rl-1803.xml b/nixos/doc/manual/release-notes/rl-1803.xml
index 12ff2e39a1bf..e7e0e4e8f25e 100644
--- a/nixos/doc/manual/release-notes/rl-1803.xml
+++ b/nixos/doc/manual/release-notes/rl-1803.xml
@@ -113,7 +113,7 @@ following incompatible changes:</para>
   </listitem>
   <listitem>
     <para>
-      <literal>cc-wrapper</literal>has been split in two; there is now also a <literal>bintools-wrapper</literal>.
+      <literal>cc-wrapper</literal> has been split in two; there is now also a <literal>bintools-wrapper</literal>.
       The most commonly used files in <filename>nix-support</filename> are now split between the two wrappers.
       Some commonly used ones, like <filename>nix-support/dynamic-linker</filename>, are duplicated for backwards compatability, even though they rightly belong only in <literal>bintools-wrapper</literal>.
       Other more obscure ones are just moved.
@@ -131,6 +131,11 @@ following incompatible changes:</para>
       Other types dependencies should be unaffected.
     </para>
   </listitem>
+  <listitem>
+    <para>
+      <literal>lib.addPassthru</literal> is removed.  Use <literal>lib.extendDerivation true</literal> instead.  <emphasis role="strong">TODO: actually remove it before branching 18.03 off.</emphasis>
+    </para>
+  </listitem>
   <listitem>
     <para>
       The <literal>memcached</literal> service no longer accept dynamic socket
diff --git a/pkgs/os-specific/linux/kernel/generic.nix b/pkgs/os-specific/linux/kernel/generic.nix
index 0d2b7655edb9..b1df6c54c456 100644
--- a/pkgs/os-specific/linux/kernel/generic.nix
+++ b/pkgs/os-specific/linux/kernel/generic.nix
@@ -134,10 +134,12 @@ let
     passthru = kernel.passthru // (removeAttrs passthru [ "passthru" ]);
   };
 
-  nativeDrv = lib.addPassthru kernel.nativeDrv passthru;
+  addPassthru' = lib.extendDerivation true passthru;
 
-  crossDrv = lib.addPassthru kernel.crossDrv passthru;
+  nativeDrv = addPassthru' kernel.nativeDrv;
+
+  crossDrv = addPassthru' kernel.crossDrv;
 
 in if kernel ? crossDrv
    then nativeDrv // { inherit nativeDrv crossDrv; }
-   else lib.addPassthru kernel passthru
+   else addPassthru' kernel
diff --git a/pkgs/stdenv/generic/check-meta.nix b/pkgs/stdenv/generic/check-meta.nix
index 6ae6e646e989..745ad14bc08b 100644
--- a/pkgs/stdenv/generic/check-meta.nix
+++ b/pkgs/stdenv/generic/check-meta.nix
@@ -1,6 +1,5 @@
-# Extend a derivation with checks for brokenness, license, etc.  Throw a
-# descriptive error when the check fails; return `derivationArg` otherwise.
-# Note: no dependencies are checked in this step.
+# Checks derivation meta and attrs for problems (like brokenness,
+# licenses, etc).
 
 { lib, config, system, meta, derivationArg, mkDerivationArg }:
 
@@ -154,12 +153,14 @@ let
 
     # Weirder stuff that doesn't appear in the documentation?
     knownVulnerabilities = listOf str;
+    name = str;
     version = str;
     tag = str;
     updateWalker = bool;
     executables = listOf str;
     outputsToInstall = listOf str;
     position = str;
+    evaluates = bool;
     repositories = attrsOf str;
     isBuildPythonPackage = platforms;
     schedulingPriority = int;
@@ -196,13 +197,11 @@ let
       { valid = false; reason = "unknown-meta"; errormsg = "has an invalid meta attrset:${lib.concatMapStrings (x: "\n\t - " + x) res}"; }
     else { valid = true; };
 
-  # Throw an error if trying to evaluate an non-valid derivation
-  validityCondition =
-         let v = checkValidity attrs;
-         in if !v.valid
-           then handleEvalIssue (removeAttrs v ["valid"])
-           else true;
+   validity = checkValidity attrs;
 
-in
-  assert validityCondition;
-  derivationArg
+in validity // {
+  # Throw an error if trying to evaluate an non-valid derivation
+  handled = if !validity.valid
+    then handleEvalIssue (removeAttrs validity ["valid"])
+    else true;
+}
diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix
index 396ed553999d..e021b284a122 100644
--- a/pkgs/stdenv/generic/make-derivation.nix
+++ b/pkgs/stdenv/generic/make-derivation.nix
@@ -81,6 +81,9 @@ rec {
       inherit erroneousHardeningFlags hardeningDisable hardeningEnable supportedHardeningFlags;
     })
     else let
+      references = nativeBuildInputs ++ buildInputs
+                ++ propagatedNativeBuildInputs ++ propagatedBuildInputs;
+
       dependencies = map (map lib.chooseDevOutputs) [
         [
           (map (drv: drv.__spliced.buildBuild or drv) depsBuildBuild)
@@ -140,9 +143,12 @@ rec {
               (lib.concatLists propagatedDependencies));
         in
         {
-          name = name + lib.optionalString
+          # A hack to make `nix-env -qa` and `nix search` ignore broken packages.
+          # TODO(@oxij): remove this assert when something like NixOS/nix#1771 gets merged into nix.
+          name = assert validity.handled; name + lib.optionalString
             (stdenv.hostPlatform != stdenv.buildPlatform)
             ("-" + stdenv.hostPlatform.config);
+
           builder = attrs.realBuilder or stdenv.shell;
           args = attrs.args or ["-e" (attrs.builder or ./default-builder.sh)];
           inherit stdenv;
@@ -197,46 +203,59 @@ rec {
           doInstallCheck = doInstallCheck && (stdenv.hostPlatform == stdenv.buildPlatform);
         });
 
+      validity = import ./check-meta.nix {
+        inherit lib config meta derivationArg;
+        mkDerivationArg = attrs;
+        # Nix itself uses the `system` field of a derivation to decide where
+        # to build it. This is a bit confusing for cross compilation.
+        inherit (stdenv) system;
+      };
+
       # The meta attribute is passed in the resulting attribute set,
       # but it's not part of the actual derivation, i.e., it's not
       # passed to the builder and is not a dependency.  But since we
       # include it in the result, it *is* available to nix-env for queries.
-      meta = { }
+      meta = {
+          # `name` above includes cross-compilation cruft (and is under assert),
+          # lets have a clean always accessible version here.
+          inherit name;
+
           # If the packager hasn't specified `outputsToInstall`, choose a default,
           # which is the name of `p.bin or p.out or p`;
           # if he has specified it, it will be overridden below in `// meta`.
           #   Note: This default probably shouldn't be globally configurable.
           #   Services and users should specify outputs explicitly,
           #   unless they are comfortable with this default.
-        // { outputsToInstall =
-          let
-            outs = outputs'; # the value passed to derivation primitive
-            hasOutput = out: builtins.elem out outs;
-          in [( lib.findFirst hasOutput null (["bin" "out"] ++ outs) )];
+          outputsToInstall =
+            let
+              outs = outputs'; # the value passed to derivation primitive
+              hasOutput = out: builtins.elem out outs;
+            in [( lib.findFirst hasOutput null (["bin" "out"] ++ outs) )];
         }
         // attrs.meta or {}
-          # Fill `meta.position` to identify the source location of the package.
-        // lib.optionalAttrs (pos != null)
-          { position = pos.file + ":" + toString pos.line; }
-        ;
+        # Fill `meta.position` to identify the source location of the package.
+        // lib.optionalAttrs (pos != null) {
+          position = pos.file + ":" + toString pos.line;
+        # Expose the result of the checks for everyone to see.
+        } // {
+          evaluates = validity.valid
+                   && (if config.checkMetaRecursively or false
+                       then lib.all (d: d.meta.evaluates or true) references
+                       else true);
+        };
 
     in
 
-      lib.addPassthru
-        (derivation (import ./check-meta.nix
-          {
-            inherit lib config meta derivationArg;
-            mkDerivationArg = attrs;
-            # Nix itself uses the `system` field of a derivation to decide where
-            # to build it. This is a bit confusing for cross compilation.
-            inherit (stdenv) system;
-          }))
-        ( {
-            overrideAttrs = f: mkDerivation (attrs // (f attrs));
-            inherit meta passthru;
-          } //
-          # Pass through extra attributes that are not inputs, but
-          # should be made available to Nix expressions using the
-          # derivation (e.g., in assertions).
-          passthru);
+      lib.extendDerivation
+        validity.handled
+        ({
+           overrideAttrs = f: mkDerivation (attrs // (f attrs));
+           inherit meta passthru;
+         } //
+         # Pass through extra attributes that are not inputs, but
+         # should be made available to Nix expressions using the
+         # derivation (e.g., in assertions).
+         passthru)
+        (derivation derivationArg);
+
 }