diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 847bfc3..ad3911e 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -837,6 +837,14 @@ function drupal_get_filename($type, $name, $filename = NULL) {
   // drupal_static().
   static $files = array(), $dirs = array();
 
+  // We use drupal_static() for the missing records so we can test it.
+  // drupal_static_fast() is used as this function may be called often.
+  static $drupal_static_fast;
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['missing'] = &drupal_static('drupal_get_filename:missing');
+  }
+  $missing = &$drupal_static_fast['missing'];
+
   // Profiles are a special case: they have a fixed location and naming.
   if ($type == 'profile') {
     $profile_filename = "profiles/$name/$name.profile";
@@ -886,7 +894,16 @@ function drupal_get_filename($type, $name, $filename = NULL) {
         $extension = $type;
       }
 
-      if (!isset($dirs[$dir][$extension])) {
+      // See if we have a cached list of files missing from the file system.
+      if (!isset($missing)) {
+        $missing = array();
+        $cache = cache_get('drupal_get_filename:missing');
+        if (!empty($cache->data)) {
+          $missing = $cache->data;
+        }
+      }
+
+      if (!isset($dirs[$dir][$extension]) && !isset($missing[$type][$name])) {
         $dirs[$dir][$extension] = TRUE;
         if (!function_exists('drupal_system_listing')) {
           require_once DRUPAL_ROOT . '/includes/common.inc';
@@ -906,6 +923,16 @@ function drupal_get_filename($type, $name, $filename = NULL) {
   if (isset($files[$type][$name])) {
     return $files[$type][$name];
   }
+  else {
+    if (!isset($missing[$type][$name])) {
+      // Add the missing file to a temporary cache and throw an alert. This cache
+      // will be cleared on cron runs as well as when visiting the module and
+      // theme list pages.
+      $missing[$type][$name] = TRUE;
+      cache_set('drupal_get_filename:missing', $missing, 'cache', REQUEST_TIME + 24 * 60 * 60);
+    }
+    trigger_error(t('The following @type is missing from the file system: @name.', array('@type' => $type, '@name' => $name)), E_USER_WARNING);
+  }
 }
 
 /**
diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test
index ece1cd9..27ca819 100644
--- a/modules/simpletest/tests/bootstrap.test
+++ b/modules/simpletest/tests/bootstrap.test
@@ -410,6 +410,35 @@ class BootstrapGetFilenameTestCase extends DrupalUnitTestCase {
     // automatically check there for 'script' files, just as it does for (e.g.)
     // 'module' files in modules.
     $this->assertIdentical(drupal_get_filename('script', 'test'), 'scripts/test.script', t('Retrieve test script location.'));
+
+    // Generate a non-existing module name.
+    $non_existing_module = uniqid("", TRUE);
+
+    // We want to save that our anonymous error handler is triggered.
+    // This variable is inherited in the error handle with 'use'.
+    $get_filename_test_triggered_error = FALSE;
+
+    // Searching for an item that does not exist returns NULL.
+    // Set a custom error handler so we can ignore the file not found error.
+    set_error_handler(function($severity, $message, $file, $line) use (&$get_filename_test_triggered_error) {
+      // Skip error handling if this is a "file not found" error.
+      if (strstr($message, 'is missing from the file system:')) {
+        $get_filename_test_triggered_error = TRUE;
+        return;
+      }
+      throw new \ErrorException($message, 0, $severity, $file, $line);
+    });
+    $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.');
+    $this->assertTrue($get_filename_test_triggered_error, 'Searching for an item that does not exist triggers an error.');
+    // Restore the original error handler.
+    restore_error_handler();
+    $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.');
+
+    // Get the bad records static from drupal_get_filename.
+    $bad = &drupal_static('drupal_get_filename:missing');
+
+    // Searching for an item that does not exist creates a static record in drupal_get_filename.
+    $this->assertTrue($bad['module'][$non_existing_module], 'Searching for an item that does not exist creates a static record in drupal_get_filename.');
   }
 }
 
diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc
index 0f525c6..7d75647 100644
--- a/modules/system/system.admin.inc
+++ b/modules/system/system.admin.inc
@@ -134,6 +134,10 @@ function system_settings_overview() {
  * Menu callback; displays a listing of all themes.
  */
 function system_themes_page() {
+  // Clean up the bootstrap "missing files" cache when listing themes.
+  drupal_static_reset('drupal_get_filename:missing');
+  cache_clear_all('drupal_get_filename:missing', 'cache');
+
   // Get current list of themes.
   $themes = system_rebuild_theme_data();
   uasort($themes, 'system_sort_modules_by_info_name');
@@ -788,6 +792,10 @@ function _system_is_incompatible(&$incompatible, $files, $file) {
  * @see system_modules_submit()
  */
 function system_modules($form, $form_state = array()) {
+  // Clean up the bootstrap "missing modules" cache when listing modules.
+  drupal_static_reset('drupal_get_filename:missing');
+  cache_clear_all('drupal_get_filename:missing', 'cache');
+
   // Get current list of modules.
   $files = system_rebuild_module_data();
 
