diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/Bundle.properties b/Core/src/com/basistech/df/cybertriage/autopsy/Bundle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..caab36116de9c8116301e01c385b5dbd5c654edd
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/Bundle.properties
@@ -0,0 +1,9 @@
+
+# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
+
+
+CTIntegrationMissingDialog.title=Cyber Triage Importer Module Required
+CTIntegrationMissingDialog.descriptionLabel.text=<html><body><p>The Cyber Triage Importer Module is required to open this case. </p><p>To open this case:</p><ul><li>Extract the module from the Integrations tab in the Cyber Triage options panel.</li><li>Select the 'Plugins' option from the 'Tools' menu, and go to the 'Downloaded' tab.</li><li>Click 'Add Plugins...' and select the path of the plugin.</li><li>Press 'Install' to finish the installation.</li></ul></body></html>
+CTIntegrationMissingDialog.docsLabel.text=<html>For more information, refer to the Cyber Triage Users Guide</html>
+CTIntegrationMissingDialog.okButton.text=OK
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/Bundle.properties-MERGED b/Core/src/com/basistech/df/cybertriage/autopsy/Bundle.properties-MERGED
new file mode 100644
index 0000000000000000000000000000000000000000..caab36116de9c8116301e01c385b5dbd5c654edd
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/Bundle.properties-MERGED
@@ -0,0 +1,9 @@
+
+# Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
+# Click nbfs://nbhost/SystemFileSystem/Templates/Other/properties.properties to edit this template
+
+
+CTIntegrationMissingDialog.title=Cyber Triage Importer Module Required
+CTIntegrationMissingDialog.descriptionLabel.text=<html><body><p>The Cyber Triage Importer Module is required to open this case. </p><p>To open this case:</p><ul><li>Extract the module from the Integrations tab in the Cyber Triage options panel.</li><li>Select the 'Plugins' option from the 'Tools' menu, and go to the 'Downloaded' tab.</li><li>Click 'Add Plugins...' and select the path of the plugin.</li><li>Press 'Install' to finish the installation.</li></ul></body></html>
+CTIntegrationMissingDialog.docsLabel.text=<html>For more information, refer to the Cyber Triage Users Guide</html>
+CTIntegrationMissingDialog.okButton.text=OK
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/CTIntegrationMissingDialog.form b/Core/src/com/basistech/df/cybertriage/autopsy/CTIntegrationMissingDialog.form
new file mode 100644
index 0000000000000000000000000000000000000000..e61f2f6cbdf1ba9d4e1c665bae3a9e278efab40f
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/CTIntegrationMissingDialog.form
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JDialogFormInfo">
+  <Properties>
+    <Property name="defaultCloseOperation" type="int" value="2"/>
+    <Property name="title" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+      <ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+    </Property>
+    <Property name="alwaysOnTop" type="boolean" value="true"/>
+    <Property name="resizable" type="boolean" value="false"/>
+  </Properties>
+  <SyntheticProperties>
+    <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
+    <SyntheticProperty name="generateCenter" type="boolean" value="false"/>
+  </SyntheticProperties>
+  <AuxValues>
+    <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
+    <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
+    <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
+    <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
+    <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,0,-65,0,0,1,-9"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+  <SubComponents>
+    <Component class="javax.swing.JLabel" name="descriptionLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[483, 116]"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="0" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="5" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Component class="javax.swing.JLabel" name="docsLabel">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.docsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+        <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[312, 16]"/>
+        </Property>
+      </Properties>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Component class="javax.swing.JLabel" name="link">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
+          <Connection code="&quot;&lt;html&gt;&lt;span style=\&quot;color: blue; text-decoration: underline\&quot;&gt;&quot; + DOCS_PAGE_URL + &quot;&lt;/span&gt;&lt;/html&gt;&quot;" type="code"/>
+        </Property>
+        <Property name="cursor" type="java.awt.Cursor" editor="org.netbeans.modules.form.editors2.CursorEditor">
+          <Color id="Hand Cursor"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="linkMouseClicked"/>
+      </Events>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="18" weightX="1.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+    <Container class="javax.swing.JPanel" name="paddingPanel">
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="2" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout>
+        <DimensionLayout dim="0">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+        <DimensionLayout dim="1">
+          <Group type="103" groupAlignment="0" attributes="0">
+              <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
+          </Group>
+        </DimensionLayout>
+      </Layout>
+    </Container>
+    <Component class="javax.swing.JButton" name="okButton">
+      <Properties>
+        <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
+          <ResourceString bundle="com/basistech/df/cybertriage/autopsy/Bundle.properties" key="CTIntegrationMissingDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
+        </Property>
+      </Properties>
+      <Events>
+        <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="okButtonActionPerformed"/>
+      </Events>
+      <AuxValues>
+        <AuxValue name="JavaCodeGenerator_VariableLocal" type="java.lang.Boolean" value="true"/>
+        <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="0"/>
+      </AuxValues>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="5" insetsBottom="5" insetsRight="5" anchor="12" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+    </Component>
+  </SubComponents>
+</Form>
diff --git a/Core/src/com/basistech/df/cybertriage/autopsy/CTIntegrationMissingDialog.java b/Core/src/com/basistech/df/cybertriage/autopsy/CTIntegrationMissingDialog.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e534c98332ac4eb0c5771dfc445515b5abd93bf
--- /dev/null
+++ b/Core/src/com/basistech/df/cybertriage/autopsy/CTIntegrationMissingDialog.java
@@ -0,0 +1,165 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 2023 Basis Technology Corp.
+ * Contact: carrier <at> sleuthkit <dot> org
+ *
+ * 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.basistech.df.cybertriage.autopsy;
+
+import java.awt.Desktop;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.logging.Level;
+import javax.swing.JComponent;
+import org.sleuthkit.autopsy.coreutils.Logger;
+
+/**
+ * Provides directions with how to enable CT integration with Autopsy when
+ * trying to open a CT exported case.
+ */
+public class CTIntegrationMissingDialog extends javax.swing.JDialog {
+
+    private static final String DOCS_PAGE_URL = "https://docs.cybertriage.com/en/latest/chapters/integrations/autopsy.html";
+
+    private static final Logger LOGGER = Logger.getLogger(CTIntegrationMissingDialog.class.getName());
+
+    /**
+     * Creates new form CTIntegrationMissingDialog
+     */
+    public CTIntegrationMissingDialog(java.awt.Frame parent, boolean modal) {
+        super(parent, modal);
+        initComponents();
+    }
+
+    /**
+     * This method is called from within the constructor to initialize the form.
+     * WARNING: Do NOT modify this code. The content of this method is always
+     * regenerated by the Form Editor.
+     */
+    @SuppressWarnings("unchecked")
+    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
+    private void initComponents() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        javax.swing.JLabel descriptionLabel = new javax.swing.JLabel();
+        javax.swing.JLabel docsLabel = new javax.swing.JLabel();
+        link = new javax.swing.JLabel();
+        javax.swing.JPanel paddingPanel = new javax.swing.JPanel();
+        javax.swing.JButton okButton = new javax.swing.JButton();
+
+        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+        setTitle(org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.title")); // NOI18N
+        setAlwaysOnTop(true);
+        setResizable(false);
+        getContentPane().setLayout(new java.awt.GridBagLayout());
+
+        org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.descriptionLabel.text")); // NOI18N
+        descriptionLabel.setMinimumSize(new java.awt.Dimension(483, 116));
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.gridwidth = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        gridBagConstraints.weightx = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
+        getContentPane().add(descriptionLabel, gridBagConstraints);
+
+        org.openide.awt.Mnemonics.setLocalizedText(docsLabel, org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.docsLabel.text")); // NOI18N
+        docsLabel.setMinimumSize(new java.awt.Dimension(312, 16));
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 1;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 0);
+        getContentPane().add(docsLabel, gridBagConstraints);
+
+        org.openide.awt.Mnemonics.setLocalizedText(link, "<html><span style=\"color: blue; text-decoration: underline\">" + DOCS_PAGE_URL + "</span></html>");
+        link.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
+        link.addMouseListener(new java.awt.event.MouseAdapter() {
+            public void mouseClicked(java.awt.event.MouseEvent evt) {
+                linkMouseClicked(evt);
+            }
+        });
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 1;
+        gridBagConstraints.gridy = 1;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        gridBagConstraints.weightx = 1.0;
+        gridBagConstraints.insets = new java.awt.Insets(0, 5, 5, 5);
+        getContentPane().add(link, gridBagConstraints);
+
+        javax.swing.GroupLayout paddingPanelLayout = new javax.swing.GroupLayout(paddingPanel);
+        paddingPanel.setLayout(paddingPanelLayout);
+        paddingPanelLayout.setHorizontalGroup(
+            paddingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 0, Short.MAX_VALUE)
+        );
+        paddingPanelLayout.setVerticalGroup(
+            paddingPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+            .addGap(0, 0, Short.MAX_VALUE)
+        );
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 2;
+        gridBagConstraints.gridwidth = 2;
+        gridBagConstraints.weighty = 1.0;
+        getContentPane().add(paddingPanel, gridBagConstraints);
+
+        org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CTIntegrationMissingDialog.class, "CTIntegrationMissingDialog.okButton.text")); // NOI18N
+        okButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                okButtonActionPerformed(evt);
+            }
+        });
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 1;
+        gridBagConstraints.gridy = 2;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
+        gridBagConstraints.insets = new java.awt.Insets(10, 5, 5, 5);
+        getContentPane().add(okButton, gridBagConstraints);
+
+        pack();
+    }// </editor-fold>//GEN-END:initComponents
+
+    private void linkMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_linkMouseClicked
+        if (Desktop.isDesktopSupported()) {
+            try {
+                Desktop.getDesktop().browse(new URI(DOCS_PAGE_URL));
+            } catch (IOException | URISyntaxException e) {
+                LOGGER.log(Level.SEVERE, "Error opening link to: " + DOCS_PAGE_URL, e);
+            }
+        } else {
+            LOGGER.log(Level.WARNING, "Desktop API is not supported.  Link cannot be opened.");
+        }
+    }//GEN-LAST:event_linkMouseClicked
+
+    private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
+        dispose();
+    }//GEN-LAST:event_okButtonActionPerformed
+
+    public void showDialog(JComponent parentComp) {
+        setLocationRelativeTo(parentComp == null ? getParent() : parentComp);
+        pack();
+        setVisible(true);
+    }
+
+    // Variables declaration - do not modify//GEN-BEGIN:variables
+    private javax.swing.JLabel link;
+    // End of variables declaration//GEN-END:variables
+}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED
index b6719401180be72a2b873a423204978798a529b3..dc96292d9a3ed409495ff76ebe59b4f28de631e3 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties-MERGED
@@ -16,6 +16,7 @@ Case.exceptionMessage.cannotDeleteCurrentCase=Cannot delete current case, it mus
 Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or host.
 Case.exceptionMessage.cannotLocateMainWindow=Cannot locate main application window
 Case.exceptionMessage.cannotOpenMultiUserCaseNoSettings=Multi-user settings are missing (see Tools, Options, Multi-user tab), cannot open a multi-user case.
+Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.
 # {0} - exception message
 Case.exceptionMessage.couldNotCreatCollaborationMonitor=Failed to create collaboration monitor:\n{0}.
 # {0} - exception message
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index 6ece795e35547c8b59b54e1d2b086b4a75efff29..b1d2f28c3137d176830956aa7bd2a13b983760b3 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -18,6 +18,7 @@
  */
 package org.sleuthkit.autopsy.casemodule;
 
+import com.basistech.df.cybertriage.autopsy.CTIntegrationMissingDialog;
 import org.sleuthkit.autopsy.featureaccess.FeatureAccessUtils;
 import com.google.common.annotations.Beta;
 import com.google.common.eventbus.Subscribe;
@@ -177,6 +178,7 @@ public class Case {
     private static final String CASE_ACTION_THREAD_NAME = "%s-case-action";
     private static final String CASE_RESOURCES_THREAD_NAME = "%s-manage-case-resources";
     private static final String NO_NODE_ERROR_MSG_FRAGMENT = "KeeperErrorCode = NoNode";
+    private static final String CT_PROVIDER_PREFIX = "CTStandardContentProvider_";
     private static final Logger logger = Logger.getLogger(Case.class.getName());
     private static final AutopsyEventPublisher eventPublisher = new AutopsyEventPublisher();
     private static final Object caseActionSerializationLock = new Object();
@@ -2729,6 +2731,7 @@ private void createCaseDatabase(ProgressIndicator progressIndicator) throws Case
         "Case.progressMessage.openingCaseDatabase=Opening case database...",
         "# {0} - exception message", "Case.exceptionMessage.couldNotOpenCaseDatabase=Failed to open case database:\n{0}.",
         "# {0} - exception message", "Case.exceptionMessage.unsupportedSchemaVersionMessage=Unsupported case database schema version:\n{0}.",
+        "Case.exceptionMessage.contentProviderCouldNotBeFound=Content provider was specified for the case but could not be loaded.",
         "Case.open.exception.multiUserCaseNotEnabled=Cannot open a multi-user case if multi-user cases are not enabled. See Tools, Options, Multi-User."
     })
     private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseActionException {
@@ -2737,14 +2740,15 @@ private void openCaseDataBase(ProgressIndicator progressIndicator) throws CaseAc
             String databaseName = metadata.getCaseDatabaseName();
             
             ContentStreamProvider contentProvider = loadContentProvider(metadata.getContentProviderName());
+            if (StringUtils.isNotBlank(metadata.getContentProviderName()) && contentProvider == null) {
+                if (metadata.getContentProviderName().trim().toUpperCase().startsWith(CT_PROVIDER_PREFIX.toUpperCase())) {
+                    new CTIntegrationMissingDialog(WindowManager.getDefault().getMainWindow(), true).showDialog(null);
+                }
+                throw new CaseActionException(Bundle.Case_exceptionMessage_contentProviderCouldNotBeFound());
+            }
             
             if (CaseType.SINGLE_USER_CASE == metadata.getCaseType()) {
-                // only prefix with metadata directory if databaseName is a relative path
-                String fullDatabasePath = (new File(databaseName).isAbsolute())
-                        ? databaseName
-                        : Paths.get(metadata.getCaseDirectory(), databaseName).toString();
-                        
-                caseDb = SleuthkitCase.openCase(fullDatabasePath, contentProvider);
+                caseDb = SleuthkitCase.openCase(metadata.getCaseDatabasePath(), contentProvider);
             } else if (UserPreferences.getIsMultiUserModeEnabled()) {
                 caseDb = SleuthkitCase.openCase(databaseName, UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory(), contentProvider);
             } else {
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java
index c9170b1e68d5a7920d265d9cebfd81a9a9c4cf32..91566a01bb0afc6f03e87db01eaf864932193ebe 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java
@@ -29,16 +29,8 @@
 import java.nio.file.Paths;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
 import java.util.Locale;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.stream.Collectors;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
@@ -51,13 +43,10 @@
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.Pair;
-import org.openide.util.Lookup;
 import org.sleuthkit.autopsy.coreutils.Version;
 import org.sleuthkit.autopsy.coreutils.XMLUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 import org.xml.sax.SAXException;
 
@@ -121,7 +110,6 @@ public final class CaseMetadata {
     private static final String SCHEMA_VERSION_SIX = "6.0";
     private final static String CONTENT_PROVIDER_ELEMENT_NAME = "ContentProvider";
     private final static String CONTENT_PROVIDER_NAME_ELEMENT_NAME = "Name";
-    private final static String CONTENT_PROVIDER_ARG_DEFAULT_KEY = "DEFAULT";
     
     /*
      * Unread fields, regenerated on save.
@@ -136,7 +124,7 @@ public final class CaseMetadata {
     private String caseName;
     private CaseDetails caseDetails;
     private String caseDatabaseName;
-    private String caseDatabasePath; // Legacy
+    private String caseDatabasePath;
     private String textIndexName; // Legacy
     private String createdDate;
     private String createdByVersion;
@@ -258,7 +246,9 @@ public Path getFilePath() {
      * @return The case directory.
      */
     public String getCaseDirectory() {
-        return metadataFilePath.getParent().toString();
+        return StringUtils.isBlank(this.caseDatabasePath)
+                ? metadataFilePath.getParent().toString()
+                : Paths.get(this.caseDatabasePath).getParent().toString();
     }
 
     /**
@@ -637,6 +627,7 @@ private void readFromFile() throws CaseMetadataException {
                     this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
                     break;
                 default:
+                    this.caseDatabasePath = getElementTextContent(caseElement, CASE_DB_ABSOLUTE_PATH_ELEMENT_NAME, false);
                     this.caseDatabaseName = getElementTextContent(caseElement, CASE_DB_NAME_RELATIVE_ELEMENT_NAME, true);
                     this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, false);
                     break;
@@ -650,11 +641,9 @@ private void readFromFile() throws CaseMetadataException {
              */
             Path possibleAbsoluteCaseDbPath = Paths.get(this.caseDatabaseName);
             Path caseDirectoryPath = Paths.get(getCaseDirectory());
-            if (possibleAbsoluteCaseDbPath.getNameCount() > 1) {
+            if (possibleAbsoluteCaseDbPath.toFile().isAbsolute()) {
                 this.caseDatabasePath = this.caseDatabaseName;
                 this.caseDatabaseName = caseDirectoryPath.relativize(possibleAbsoluteCaseDbPath).toString();
-            } else {
-                this.caseDatabasePath = caseDirectoryPath.resolve(caseDatabaseName).toAbsolutePath().toString();
             }
 
         } catch (ParserConfigurationException | SAXException | IOException ex) {
@@ -719,12 +708,12 @@ private CaseMetadataException(String message, Throwable cause) {
      * @return The full path to the case database file for a single-user case.
      *
      * @throws UnsupportedOperationException If called for a multi-user case.
-     * @deprecated Do not use.
      */
-    @Deprecated
     public String getCaseDatabasePath() throws UnsupportedOperationException {
         if (Case.CaseType.SINGLE_USER_CASE == caseType) {
-            return Paths.get(getCaseDirectory(), caseDatabaseName).toString();
+            return StringUtils.isBlank(this.caseDatabasePath)
+                    ? this.metadataFilePath.getParent().resolve(this.caseDatabaseName).toString()
+                    : this.caseDatabasePath;
         } else {
             throw new UnsupportedOperationException();
         }