diff --git a/doc/source/pycgtool.parsers.json.rst b/doc/source/pycgtool.parsers.json.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f761daeea7be5ac827e8cc2a49b65b5c4ca09fca
--- /dev/null
+++ b/doc/source/pycgtool.parsers.json.rst
@@ -0,0 +1,7 @@
+pycgtool.parsers.json module
+============================
+
+.. automodule:: pycgtool.parsers.json
+    :members:
+    :undoc-members:
+    :show-inheritance:
diff --git a/doc/source/pycgtool.parsers.rst b/doc/source/pycgtool.parsers.rst
index e1fea8bc63eac01873b1086edc5c340901688454..1bf99ceac6b2b731a7cf3eef1ae3f0d9a336821d 100644
--- a/doc/source/pycgtool.parsers.rst
+++ b/doc/source/pycgtool.parsers.rst
@@ -7,6 +7,7 @@ Submodules
 .. toctree::
 
    pycgtool.parsers.cfg
+   pycgtool.parsers.json
 
 Module contents
 ---------------
diff --git a/pycgtool/parsers/json.py b/pycgtool/parsers/json.py
index bbfe9aefac4a0a837e54943ef770bc92355b254a..9fc342fb09e8bb5061e57a1afad858048c36b987 100644
--- a/pycgtool/parsers/json.py
+++ b/pycgtool/parsers/json.py
@@ -2,23 +2,34 @@ import json
 import os
 
 
-class Record(dict):
-    def __setattr__(self, key, value):
-        self[key] = value
-
-    def __getattr__(self, item):
-        return self[item]
+class AttrDict(dict):
+    """
+    Class allowing dictionary entries to be accessed as attributes as well as keys.
+    """
+    def __init__(self, *args, **kwargs):
+        super(AttrDict, self).__init__(*args, **kwargs)
+        self.__dict__ = self
 
 
 class CFG:
+    """
+    Class to read data from JSON files.  Supports including other files and filtering a single section.
+    """
     def __init__(self, filename, from_section=None):
+        """
+        Create a new CFG JSON parser.
+
+        :param filename: JSON file to read
+        :param from_section: Optional section to select from file
+        """
         with open(filename) as f:
-            self._json = json.load(f, object_hook=Record)
+            self._json = json.load(f, object_hook=AttrDict)
 
+        # Recurse through include lists and add to self._json
         while self._json.include:
             include_file = os.path.join(os.path.dirname(filename), self._json.include.pop())
             with open(include_file) as include_file:
-                include_json = json.load(include_file, object_hook=Record)
+                include_json = json.load(include_file, object_hook=AttrDict)
 
             for curr, incl in zip(self._json.values(), include_json.values()):
                 try:
@@ -26,10 +37,13 @@ class CFG:
                 except TypeError:
                     curr.update(incl)
 
+        self._records = self._json
         if from_section is not None:
-            self._records = self._json[from_section]
-        else:
-            self._records = self._json
+            try:
+                self._records = self._json[from_section]
+            except KeyError as e:
+                e.args = ("Section '{0}' not in file '{1}'".format(from_section, filename),)
+                raise
 
     def __getitem__(self, item):
         return self._records[item]
diff --git a/test/test_parsers_json.py b/test/test_parsers_json.py
index c6f6c057461f31749fc281d8e8657e9d55c2c979..5878d96d71f4ef2cb464baba5b2cc2547c15b8b8 100644
--- a/test/test_parsers_json.py
+++ b/test/test_parsers_json.py
@@ -49,6 +49,10 @@ class TestParsersJson(unittest.TestCase):
         self.assertTrue("DOPC" in cfg)
         self.assertTrue("GLY" in cfg)
 
+    def test_missing_section(self):
+        with self.assertRaises(KeyError):
+            cfg = CFG("test/data/water.json", "potato")
+
 
 if __name__ == '__main__':
     unittest.main()