diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Revision history for selda
 
+## 0.1.3.2 -- 2017-05-01
+
+* Only throw well-documented, Selda-specific exceptions.
+
 ## 0.1.3.1 -- 2017-05-01
 
 * More hackage-friendly README.
diff --git a/selda.cabal b/selda.cabal
--- a/selda.cabal
+++ b/selda.cabal
@@ -1,5 +1,5 @@
 name:                selda
-version:             0.1.3.1
+version:             0.1.3.2
 synopsis:            Type-safe, high-level EDSL for interacting with relational databases.
 description:         This package provides an EDSL for writing portable, type-safe, high-level
                      database code. Its feature set includes querying and modifying databases,
diff --git a/src/Database/Selda.hs b/src/Database/Selda.hs
--- a/src/Database/Selda.hs
+++ b/src/Database/Selda.hs
@@ -2,10 +2,68 @@
 -- | Selda is not LINQ, but they're definitely related.
 --
 --   Selda is a high-level EDSL for interacting with relational databases.
---   Please see <https://github.com/valderman/selda/> for a brief tutorial.
+--   All database computations are performed within some monad implementing
+--   the 'MonadSelda' type class. The 'SeldaT' monad over any @MonadIO@ is the
+--   only pre-defined instance of @MonadSelda@.
+--   'SeldaM' is provided as a convenient short-hand for @SeldaT IO@.
+--
+--   To actually execute a database computation, you need one of the database
+--   backends: @selda-sqlite@ or @selda-postgresql@.
+--
+--   All Selda functions may throw 'SeldaError' when something goes wrong.
+--   This includes database connection errors, uniqueness constraint errors,
+--   etc.
+--
+--   The following example shows off Selda's most basic features -- creating,
+--   populating, modifying and querying tables -- and is intended to act as a
+--   Hello World-ish quickstart.
+--
+-- > {-# LANGUAGE TypeOperators, OverloadedStrings #-}
+-- > import Data.Text (Text, unpack)
+-- > import Database.Selda
+-- > import Database.Selda.SQLite
+-- >
+-- > people :: Table (Text :*: Int :*: Maybe Text)
+-- > (people, pName :*: pAge :*: pPet)
+-- >   = tableWithSelectors "people"
+-- >   $   primary "name"
+-- >   :*: required "age"
+-- >   :*: optional "pet"
+-- >
+-- > main = withSQLite "people.sqlite" $ do
+-- >   createTable people
+-- >
+-- >   insert_ people
+-- >     [ "Velvet"    :*: 19 :*: Nothing
+-- >     , "Kobayashi" :*: 23 :*: Just "dragon"
+-- >     , "Miyu"      :*: 10 :*: Nothing
+-- >     ]
+-- >
+-- >   update_ people
+-- >     (\person -> person ! pName .== "Velvet")
+-- >     (\person -> person `with` [pPet := just "orthros"])
+-- >
+-- >   adults <- query $ do
+-- >     person <- select people
+-- >     restrict (person ! pAge .> 20)
+-- >     return (person ! pName :*: person ! pAge)
+-- >
+-- >   n <- deleteFrom people (\person -> isNull (person ! pPet))
+-- >
+-- >   liftIO $ do
+-- >     putStrLn "The adults in the room are:"
+-- >     mapM_ printPerson adults
+-- >     putStrLn $ show n ++ " people were deleted for having no pets."
+-- >
+-- > printPerson :: Text :*: Int -> IO ()
+-- > printPerson (name :*: age) = putStrLn $ unpack name ++ ", age " ++ show age
+--
+--   Please see <http://hackage.haskell.org/package/selda/#readme>
+--   for a more comprehensive tutorial.
 module Database.Selda
   ( -- * Running queries
     MonadIO (..), MonadSelda
+  , SeldaError (..), ValidationError
   , SeldaT, SeldaM, Table, Query, Col, Res, Result
   , query, transaction, setLocalCache
     -- * Constructing queries
diff --git a/src/Database/Selda/Backend.hs b/src/Database/Selda/Backend.hs
--- a/src/Database/Selda/Backend.hs
+++ b/src/Database/Selda/Backend.hs
@@ -3,6 +3,7 @@
 module Database.Selda.Backend
   ( MonadIO (..)
   , QueryRunner, SeldaBackend (..), MonadSelda (..), SeldaT (..), SeldaM
+  , SeldaError (..)
   , Param (..), Lit (..), SqlValue (..), ColAttr (..)
   , compileColAttr
   , sqlDateTimeFormat, sqlDateFormat, sqlTimeFormat
@@ -16,6 +17,15 @@
 import Control.Monad.IO.Class
 import Control.Monad.State
 import Data.Text (Text)
+import Data.Typeable
+
+-- | Thrown by any function in 'SeldaT' if an error occurs.
+data SeldaError
+  = DbError String  -- ^ Unable to open or connect to database.
+  | SqlError String -- ^ An error occurred while executing query.
+  deriving (Show, Eq, Typeable)
+
+instance Exception SeldaError
 
 -- | A function which executes a query and gives back a list of extensible
 --   tuples; one tuple per result row, and one tuple element per column.
diff --git a/src/Database/Selda/Table.hs b/src/Database/Selda/Table.hs
--- a/src/Database/Selda/Table.hs
+++ b/src/Database/Selda/Table.hs
@@ -5,11 +5,25 @@
 module Database.Selda.Table where
 import Database.Selda.Types
 import Database.Selda.SqlType
+import Control.Exception
 import Data.Dynamic
 import Data.List (sort, group)
 import Data.Monoid
 import Data.Text (Text, unpack, intercalate, any)
+import Data.Typeable
 
+-- | An error occurred when validating a database table.
+--   If this error is thrown, there is a bug in your database schema, and the
+--   particular table that triggered the error is unusable.
+--   Since validation is deterministic, this error will be thrown on every
+--   consecutive operation over the offending table.
+--
+--   Therefore, it is not meaningful to handle this exception in any way,
+--   just fix your bug instead.
+data ValidationError = ValidationError String
+  deriving (Show, Eq, Typeable)
+instance Exception ValidationError
+
 -- | A database table.
 --   Tables are parameterized over their column types. For instance, a table
 --   containing one string and one integer, in that order, would have the type
@@ -126,7 +140,7 @@
 validate :: TableName -> [ColInfo] -> [ColInfo]
 validate name cis
   | null errs = cis
-  | otherwise = error $ concat
+  | otherwise = throw $ ValidationError $ concat
       [ "validation of table ", unpack $ fromTableName name, " failed:"
       , "\n  "
       , unpack $ intercalate "\n  " errs
