diff --git a/common/design_block_io.cpp b/common/design_block_io.cpp
index 912c4acada..e25acbad2e 100644
--- a/common/design_block_io.cpp
+++ b/common/design_block_io.cpp
@@ -74,8 +74,10 @@ DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T
 DESIGN_BLOCK_IO_MGR::GuessPluginTypeFromLibPath( const wxString& aLibPath, int aCtl )
 {
     if( IO_RELEASER<DESIGN_BLOCK_IO>( FindPlugin( KICAD_SEXP ) )->CanReadLibrary( aLibPath )
-      && aCtl != KICTL_NONKICAD_ONLY )
+            && aCtl != KICTL_NONKICAD_ONLY )
+    {
         return KICAD_SEXP;
+    }
 
     return DESIGN_BLOCK_IO_MGR::FILE_TYPE_NONE;
 }
diff --git a/eeschema/erc/erc.cpp b/eeschema/erc/erc.cpp
index 777019f0f9..dd1372b9df 100644
--- a/eeschema/erc/erc.cpp
+++ b/eeschema/erc/erc.cpp
@@ -1387,8 +1387,8 @@ int ERC_TESTER::TestLibSymbolIssues()
 
             wxCHECK2( libSymbolInSchematic, continue );
 
-            wxString       libName = symbol->GetLibId().GetLibNickname();
-            LIB_TABLE_ROW* libTableRow = libTable->FindRow( libName, true );
+            wxString             libName = symbol->GetLibId().GetLibNickname();
+            const LIB_TABLE_ROW* libTableRow = libTable->FindRow( libName, true );
 
             if( !libTableRow )
             {
@@ -1411,7 +1411,7 @@ int ERC_TESTER::TestLibSymbolIssues()
                 {
                     std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LIB_SYMBOL_ISSUES );
                     ercItem->SetItems( symbol );
-                    msg.Printf( _( "The library '%s' is not enabled in the current configuration" ),
+                    msg.Printf( _( "The symbol library '%s' is not enabled in the current configuration" ),
                                 UnescapeString( libName ) );
                     ercItem->SetErrorMessage( msg );
 
@@ -1420,6 +1420,22 @@ int ERC_TESTER::TestLibSymbolIssues()
 
                 continue;
             }
+            else if( !libTableRow->LibraryExists() )
+            {
+                if( m_settings.IsTestEnabled( ERCE_LIB_SYMBOL_ISSUES ) )
+                {
+                    std::shared_ptr<ERC_ITEM> ercItem = ERC_ITEM::Create( ERCE_LIB_SYMBOL_ISSUES );
+                    ercItem->SetItems( symbol );
+                    msg.Printf( _( "The symbol library '%s' was not found at '%s'." ),
+                                UnescapeString( libName ),
+                                libTableRow->GetFullURI( true ) );
+                    ercItem->SetErrorMessage( msg );
+
+                    markers.emplace_back( new SCH_MARKER( ercItem, symbol->GetPosition() ) );
+                }
+
+                continue;
+            }
 
             wxString    symbolName = symbol->GetLibId().GetLibItemName();
             LIB_SYMBOL* libSymbol = SchGetLibSymbol( symbol->GetLibId(), libTable );
diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp
index 6fa80445f6..1eb23fe2b7 100644
--- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp
+++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.cpp
@@ -1697,9 +1697,7 @@ void SCH_IO_KICAD_SEXPR::SaveLibrary( const wxString& aLibraryPath,
     wxString oldFileName = m_cache->GetFileName();
 
     if( !m_cache->IsFile( aLibraryPath ) )
-    {
         m_cache->SetFileName( aLibraryPath );
-    }
 
     // This is a forced save.
     m_cache->SetModified();
@@ -1708,6 +1706,18 @@ void SCH_IO_KICAD_SEXPR::SaveLibrary( const wxString& aLibraryPath,
 }
 
 
+bool SCH_IO_KICAD_SEXPR::CanReadLibrary( const wxString& aLibraryPath ) const
+{
+    if( !SCH_IO::CanReadLibrary( aLibraryPath ) )
+        return false;
+
+    // Above just checks for proper extension; now check that it actually exists
+
+    wxFileName fn( aLibraryPath );
+    return fn.IsOk() && fn.FileExists();
+}
+
+
 bool SCH_IO_KICAD_SEXPR::IsLibraryWritable( const wxString& aLibraryPath )
 {
     wxFileName fn( aLibraryPath );
@@ -1785,7 +1795,6 @@ std::vector<LIB_SYMBOL*> SCH_IO_KICAD_SEXPR::ParseLibSymbols( std::string& aSymb
 
 void SCH_IO_KICAD_SEXPR::FormatLibSymbol( LIB_SYMBOL* symbol, OUTPUTFORMATTER & formatter )
 {
-
     LOCALE_IO toggle;     // toggles on, then off, the C locale.
     SCH_IO_KICAD_SEXPR_LIB_CACHE::SaveSymbol( symbol, formatter );
 }
diff --git a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h
index 43816daa7b..ec44df1b3b 100644
--- a/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h
+++ b/eeschema/sch_io/kicad_sexpr/sch_io_kicad_sexpr.h
@@ -125,6 +125,8 @@ public:
     void SaveLibrary( const wxString& aLibraryPath,
                       const std::map<std::string, UTF8>* aProperties = nullptr ) override;
 
+    bool CanReadLibrary( const wxString& aLibraryPath ) const override;
+
     bool IsLibraryWritable( const wxString& aLibraryPath ) override;
 
     void GetAvailableSymbolFields( std::vector<wxString>& aNames ) override;
diff --git a/eeschema/symbol_lib_table.h b/eeschema/symbol_lib_table.h
index cdfbff340d..202540ebb5 100644
--- a/eeschema/symbol_lib_table.h
+++ b/eeschema/symbol_lib_table.h
@@ -115,6 +115,14 @@ public:
             plugin->GetDefaultSymbolFields( aNames );
     }
 
+    bool LibraryExists() const override
+    {
+        if( plugin )
+            return plugin->CanReadLibrary( GetFullURI( true ) );
+
+        return false;
+    }
+
     SCH_IO_MGR::SCH_FILE_T GetFileType() { return type; }
 
 protected:
diff --git a/include/design_block_lib_table.h b/include/design_block_lib_table.h
index cfb831e6ce..dbbfbbfbc7 100644
--- a/include/design_block_lib_table.h
+++ b/include/design_block_lib_table.h
@@ -69,6 +69,14 @@ public:
      */
     void SetType( const wxString& aType ) override;
 
+    bool LibraryExists() const override
+    {
+        if( plugin )
+            return plugin->CanReadLibrary( GetFullURI( true ) );
+
+        return false;
+    }
+
     DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T GetFileType() { return type; }
 
 protected:
diff --git a/include/fp_lib_table.h b/include/fp_lib_table.h
index 5850d9d354..8f355eebd2 100644
--- a/include/fp_lib_table.h
+++ b/include/fp_lib_table.h
@@ -67,7 +67,7 @@ public:
      */
     void SetType( const wxString& aType ) override;
 
-    bool LibraryExists() const;
+    bool LibraryExists() const override;
 
     PCB_IO_MGR::PCB_FILE_T GetFileType() { return type; }
 
diff --git a/include/io/io_base.h b/include/io/io_base.h
index 34514d28e6..3388c2c410 100644
--- a/include/io/io_base.h
+++ b/include/io/io_base.h
@@ -114,9 +114,6 @@ public:
     /**
      * Checks if this IO object can read the specified library file/directory.
      * If not overridden, extension check is used.
-     *
-     * @note This is not a check that the file system object is readable by the user,
-     *       but a check that this IO object can parse the given library.
      */
     virtual bool CanReadLibrary( const wxString& aFileName ) const;
 
diff --git a/include/lib_table_base.h b/include/lib_table_base.h
index 3ba27e02b3..d3b94783f1 100644
--- a/include/lib_table_base.h
+++ b/include/lib_table_base.h
@@ -188,6 +188,8 @@ public:
 
     void SetVisible( bool aVisible = true ) { visible = aVisible; }
 
+    virtual bool LibraryExists() const = 0;
+
     virtual bool Refresh() { return false; }
 
     /**
diff --git a/pcbnew/drc/drc_test_provider_library_parity.cpp b/pcbnew/drc/drc_test_provider_library_parity.cpp
index 39d8f1bf39..3a8da66edc 100644
--- a/pcbnew/drc/drc_test_provider_library_parity.cpp
+++ b/pcbnew/drc/drc_test_provider_library_parity.cpp
@@ -837,10 +837,10 @@ bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
         if( !reportProgress( ii++, (int) board->Footprints().size(), progressDelta ) )
             return false;   // DRC cancelled
 
-        LIB_ID                  fpID = footprint->GetFPID();
-        wxString                libName = fpID.GetLibNickname();
-        wxString                fpName = fpID.GetLibItemName();
-        const FP_LIB_TABLE_ROW* libTableRow = nullptr;
+        LIB_ID               fpID = footprint->GetFPID();
+        wxString             libName = fpID.GetLibNickname();
+        wxString             fpName = fpID.GetLibItemName();
+        const LIB_TABLE_ROW* libTableRow = nullptr;
 
         if( libName.IsEmpty() )
         {
@@ -862,7 +862,7 @@ bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
             {
                 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
                 msg.Printf( _( "The current configuration does not include the footprint library '%s'." ),
-                            libName );
+                            UnescapeString( libName ) );
                 drcItem->SetErrorMessage( msg );
                 drcItem->SetItems( footprint );
                 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
@@ -876,7 +876,7 @@ bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
             {
                 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
                 msg.Printf( _( "The footprint library '%s' is not enabled in the current configuration." ),
-                            libName );
+                            UnescapeString( libName ) );
                 drcItem->SetErrorMessage( msg );
                 drcItem->SetItems( footprint );
                 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
@@ -889,8 +889,9 @@ bool DRC_TEST_PROVIDER_LIBRARY_PARITY::Run()
             if( !m_drcEngine->IsErrorLimitExceeded( DRCE_LIB_FOOTPRINT_ISSUES ) )
             {
                 std::shared_ptr<DRC_ITEM> drcItem = DRC_ITEM::Create( DRCE_LIB_FOOTPRINT_ISSUES );
-                msg.Printf( _( "The footprint library '%s' was not found." ),
-                            libName );
+                msg.Printf( _( "The footprint library '%s' was not found at '%s'." ),
+                            UnescapeString( libName ),
+                            libTableRow->GetFullURI( true ) );
                 drcItem->SetErrorMessage( msg );
                 drcItem->SetItems( footprint );
                 reportViolation( drcItem, footprint->GetCenter(), UNDEFINED_LAYER );
diff --git a/pcbnew/pcb_io/pcb_io.h b/pcbnew/pcb_io/pcb_io.h
index cb07d6ad8c..3562bf268d 100644
--- a/pcbnew/pcb_io/pcb_io.h
+++ b/pcbnew/pcb_io/pcb_io.h
@@ -126,7 +126,8 @@ public:
      *                 possible.
      */
     virtual BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
-                         const std::map<std::string, UTF8>* aProperties = nullptr, PROJECT* aProject = nullptr );
+                              const std::map<std::string, UTF8>* aProperties = nullptr,
+                              PROJECT* aProject = nullptr );
 
     /**
      * Return a container with the cached library footprints generated in the last call to
@@ -174,7 +175,8 @@ public:
      * @throw IO_ERROR if the library cannot be found, or footprint cannot be loaded.
      */
     virtual void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
-                                     bool aBestEfforts, const std::map<std::string, UTF8>* aProperties = nullptr );
+                                     bool aBestEfforts,
+                                     const std::map<std::string, UTF8>* aProperties = nullptr );
 
     /**
      * Generate a timestamp representing all the files in the library (including the library
diff --git a/qa/tests/common/test_lib_table.cpp b/qa/tests/common/test_lib_table.cpp
index 8d8abfea4c..2645aa6ae9 100644
--- a/qa/tests/common/test_lib_table.cpp
+++ b/qa/tests/common/test_lib_table.cpp
@@ -83,15 +83,10 @@ public:
     {
     }
 
-    const wxString GetType() const override
-    {
-        return m_type;
-    }
+    const wxString GetType() const override { return m_type; }
+    void SetType( const wxString& aType ) override { m_type = aType; }
 
-    void SetType( const wxString& aType ) override
-    {
-        m_type = aType;
-    }
+    bool LibraryExists() const override { return true; }
 
 private:
     LIB_TABLE_ROW* do_clone() const override