diff --git a/amazonka.cabal b/amazonka.cabal
--- a/amazonka.cabal
+++ b/amazonka.cabal
@@ -1,5 +1,5 @@
 name:                  amazonka
-version:               1.0.1
+version:               1.1.0
 synopsis:              Comprehensive Amazon Web Services SDK
 homepage:              https://github.com/brendanhay/amazonka
 license:               OtherLicense
@@ -27,11 +27,6 @@
     * "Network.AWS": The 'AWS' monad and 'MonadAWS' type class for automatically
     lifting operations when embedded as a layer in a transformer stack.
     .
-    Both 'Control.Monad.Trans.AWS.AWST' and 'Network.AWS.AWS' provide functions
-    that are built upon a 'MonadFree' 'Command' DSL defined in
-    "Network.AWS.Free". This allows writing a custom interpreter (say, for
-    mocking purposes) and defining your own AWS logic if desired.
-    .
     GHC 7.8.4 and higher is officially supported.
 
 source-repository head
@@ -51,7 +46,6 @@
         , Network.AWS.Data
         , Network.AWS.EC2.Metadata
         , Network.AWS.Env
-        , Network.AWS.Free
         , Network.AWS.Presign
 
     other-modules:
@@ -60,14 +54,13 @@
         , Network.AWS.Internal.Logger
 
     build-depends:
-          amazonka-core       == 1.0.1.*
+          amazonka-core       == 1.1.0.*
         , base                >= 4.7     && < 5
         , bytestring          >= 0.9
         , conduit             >= 1.1
         , conduit-extra       >= 1.1
         , directory           >= 1.2
         , exceptions          >= 0.6
-        , free                >= 4.5
         , http-client         >= 0.4.9
         , http-conduit        >= 2.1.4
         , ini                 >= 0.2
diff --git a/src/Control/Monad/Trans/AWS.hs b/src/Control/Monad/Trans/AWS.hs
--- a/src/Control/Monad/Trans/AWS.hs
+++ b/src/Control/Monad/Trans/AWS.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE BangPatterns               #-}
+{-# LANGUAGE ConstraintKinds            #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE FlexibleInstances          #-}
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
@@ -7,7 +8,6 @@
 {-# LANGUAGE RankNTypes                 #-}
 {-# LANGUAGE TypeFamilies               #-}
 {-# LANGUAGE UndecidableInstances       #-}
-{-# LANGUAGE ViewPatterns               #-}
 
 {-# OPTIONS_GHC -fno-warn-duplicate-exports #-}
 
@@ -20,19 +20,17 @@
 -- Portability : non-portable (GHC extensions)
 --
 -- The 'AWST' transformer provides the environment required to perform AWS
--- operations and constructs a 'Command' AST using 'MonadFree' which can then be
--- interpreted using 'runAWST'. The transformer is intended to be used directly
+-- operations. The transformer is intended to be used directly
 -- or embedded as a layer within a transformer stack.
 --
--- "Network.AWS" contains a 'IO' specialised version of 'AWST' with a typeclass
+-- "Network.AWS" contains an 'IO' specialised version of 'AWST' with a typeclass
 -- to assist in automatically lifting operations.
 module Control.Monad.Trans.AWS
     (
     -- * Running AWS Actions
       AWST
     , runAWST
-    , execAWST
-    , hoistAWST
+    , AWSConstraint
 
     -- * Authentication and Environment
     , newEnv
@@ -132,7 +130,6 @@
     , newLogger
 
     -- * Re-exported Types
-    , Command
     , RqBody
     , RsBody
     , module Network.AWS.Types
@@ -147,31 +144,29 @@
 import           Control.Exception.Lens
 import           Control.Monad.Base
 import           Control.Monad.Catch
-import           Control.Monad.Error.Class       (MonadError (..))
-import           Control.Monad.Morph             (hoist)
+import           Control.Monad.Error.Class    (MonadError (..))
+import           Control.Monad.Morph
 import           Control.Monad.Reader
 import           Control.Monad.State.Class
 import           Control.Monad.Trans.Control
-import           Control.Monad.Trans.Free        (FreeF (Pure), FreeT (..))
-import           Control.Monad.Trans.Free.Church
 import           Control.Monad.Trans.Resource
 import           Control.Monad.Writer.Class
+import           Data.Conduit                 hiding (await)
 import           Data.IORef
 import           Network.AWS.Auth
-import qualified Network.AWS.EC2.Metadata        as EC2
+import qualified Network.AWS.EC2.Metadata     as EC2
 import           Network.AWS.Env
-import           Network.AWS.Free
 import           Network.AWS.Internal.Body
 import           Network.AWS.Internal.HTTP
 import           Network.AWS.Internal.Logger
-import           Network.AWS.Pager               (AWSPager)
-import           Network.AWS.Prelude             as AWS
-import qualified Network.AWS.Presign             as Sign
-import           Network.AWS.Types               hiding (LogLevel (..))
-import           Network.AWS.Waiter              (Wait)
+import           Network.AWS.Pager            (AWSPager (..))
+import           Network.AWS.Prelude          as AWS
+import qualified Network.AWS.Presign          as Sign
+import           Network.AWS.Types            hiding (LogLevel (..))
+import           Network.AWS.Waiter           (Wait)
 
 -- | The 'AWST' transformer.
-newtype AWST m a = AWST { unAWST :: FT Command (ReaderT Env m) a }
+newtype AWST m a = AWST { unAWST :: ReaderT Env m a }
     deriving
         ( Functor
         , Applicative
@@ -179,7 +174,6 @@
         , Monad
         , MonadPlus
         , MonadIO
-        , MonadFree Command
         , MonadReader Env
         )
 
@@ -192,20 +186,20 @@
 instance MonadBase b m => MonadBase b (AWST m) where
     liftBase = liftBaseDefault
 
-instance MonadBaseControl b m => MonadBaseControl b (AWST m) where
-    type StM (AWST m) a =
-         StM m (FreeF Command a (FreeT Command (ReaderT Env m) a))
+instance MonadTransControl AWST where
+    type StT AWST a = StT (ReaderT Env) a
 
-    liftBaseWith f = AWST . toFT . FreeT . liftM Pure $
-        liftBaseWith $ \runInBase ->
-            f $ \k ->
-                runInBase $
-                    runFreeT (fromFT (unAWST k))
+    liftWith = defaultLiftWith AWST unAWST
+    restoreT = defaultRestoreT AWST
 
-    restoreM = AWST . toFT . FreeT . restoreM
+instance MonadBaseControl b m => MonadBaseControl b (AWST m) where
+    type StM (AWST m) a = ComposeSt AWST m a
 
+    liftBaseWith = defaultLiftBaseWith
+    restoreM     = defaultRestoreM
+
 instance MonadTrans AWST where
-    lift = AWST . lift . lift
+    lift = AWST . lift
 
 instance MonadResource m => MonadResource (AWST m) where
     liftResourceT = lift . liftResourceT
@@ -224,83 +218,194 @@
     listen = AWST . listen . unAWST
     pass   = AWST . pass   . unAWST
 
+instance MFunctor AWST where
+    hoist nat = AWST . hoist nat . unAWST
+
 -- | Run an 'AWST' action with the specified 'HasEnv' environment.
--- Any outstanding HTTP responses' 'ResumableSource' will
--- be closed when the 'ResourceT' computation is unwrapped with 'runResourceT'.
+runAWST :: HasEnv r => r -> AWST m a -> m a
+runAWST r (AWST m) = runReaderT m (r ^. environment)
+
+-- | An alias for the constraints required to send requests,
+-- which 'AWST' implicitly fulfils.
+type AWSConstraint r m =
+    ( MonadCatch     m
+    , MonadResource  m
+    , MonadReader  r m
+    , HasEnv       r
+    )
+
+-- | Send a request, returning the associated response if successful.
 --
--- Throws 'Error' during interpretation of the underlying 'MonadFree' 'Command' AST.
+-- Throws 'Error'.
 --
--- /See:/ 'runResourceT'.
-runAWST :: (MonadCatch m, MonadResource m, HasEnv r) => r -> AWST m a -> m a
-runAWST = execAWST hoistError
+-- /See:/ 'sendWith'
+send :: (AWSConstraint r m, AWSRequest a)
+     => a
+     -> m (Rs a)
+send = sendWith id
 
--- | Run an 'AWST' action with configurable 'Error' handling.
+-- | A variant of 'send' that allows modifying the default 'Service' definition
+-- used to configure the request.
 --
--- Does not explictly throw 'Error's and instead uses the supplied lift function.
-execAWST :: (MonadCatch m, MonadResource m, HasEnv r)
-         => (forall a. Either Error a -> m a)
-            -- ^ Lift an 'Error' into the base Monad.
-         -> r
-         -> AWST m b
-         -> m b
-execAWST f = innerAWST go
+-- Throws 'Error'.
+sendWith :: (AWSConstraint r m, AWSSigner (Sg s), AWSRequest a)
+         => (Service (Sv a) -> Service s) -- ^ Modify the default service configuration.
+         -> a                             -- ^ Request.
+         -> m (Rs a)
+sendWith f x = do
+    e <- view environment
+    r <- retrier e s rq (perform e s rq) >>= hoistError
+    return (snd r)
   where
-    go (CheckF k) = do
-        io <- view envEC2
-        mp <- liftIO (readIORef io)
-        case mp of
-            Just p  -> k p
-            Nothing -> do
-                m  <- view envManager
-                !r <- lift . f =<< tryT (EC2.isEC2 m)
-                liftIO (atomicWriteIORef io (Just r))
-                k r
+    rq = request x
+    s  = f (serviceOf x)
 
-    go (DynF x k) = do
-        m <- view envManager
-        r <- lift . f =<< tryT (EC2.dynamic m x)
-        k r
+-- | Repeatedly send a request, automatically setting markers and
+-- paginating over multiple responses while available.
+--
+-- Throws 'Error'.
+--
+-- /See:/ 'paginateWith'
+paginate :: (AWSConstraint r m, AWSPager a)
+         => a
+         -> Source m (Rs a)
+paginate = paginateWith id
 
-    go (MetaF x k) = do
-        m <- view envManager
-        r <- lift . f =<< tryT (EC2.metadata m x)
-        k r
+-- | A variant of 'paginate' that allows modifying the default 'Service' definition
+-- used to configure the request.
+--
+-- Throws 'Error'.
+paginateWith :: (AWSConstraint r m, AWSSigner (Sg s), AWSPager a)
+             => (Service (Sv a) -> Service s) -- ^ Modify the default service configuration.
+             -> a                             -- ^ Initial request.
+             -> Source m (Rs a)
+paginateWith f = go
+  where
+    go !x = do
+        !y <- sendWith f x
+        yield y
+        maybe (pure ())
+              go
+              (page x y)
 
-    go (UserF k) = do
-        m <- view envManager
-        r <- lift . f =<< tryT (EC2.userdata m)
-        k r
+-- | Poll the API with the supplied request until a specific 'Wait' condition
+-- is fulfilled.
+--
+-- Throws 'Error'.
+--
+-- /See:/ 'awaitWith'
+await :: (AWSConstraint r m, AWSRequest a)
+      => Wait a
+      -> a
+      -> m ()
+await = awaitWith id
 
-    go (SignF s ts ex x k) = do
-        a <- view envAuth
-        g <- view envRegion
-        r <- Sign.presignWith (const s) a g ts ex x
-        k r
+-- | A variant of 'await' that allows modifying the default 'Service' definition
+-- used to configure the request.
+--
+-- Throws 'Error'.
+awaitWith :: (AWSConstraint r m, AWSSigner (Sg s), AWSRequest a)
+          => (Service (Sv a) -> Service s) -- ^ Modify the default service configuration.
+          -> Wait a                        -- ^ Polling, error and acceptance criteria.
+          -> a                             -- ^ Request to poll with.
+          -> m ()
+awaitWith f w x = do
+    e <- view environment
+    waiter e w rq (perform e s rq) >>= hoistError . maybe (Right ()) Left
+  where
+    rq = request x
+    s  = f (serviceOf x)
 
-    go (SendF s (request -> x) k) = do
-        e <- view environment
-        r <- lift . f =<< retrier e s x (perform e s x)
-        k (snd r)
+-- | Presign an URL that is valid from the specified time until the
+-- number of seconds expiry has elapsed.
+--
+-- /See:/ 'presign', 'presignWith'
+presignURL :: ( MonadIO m
+              , MonadReader r m
+              , HasEnv r
+              , AWSPresigner (Sg (Sv a))
+              , AWSRequest a
+              )
+           => UTCTime     -- ^ Signing time.
+           -> Seconds     -- ^ Expiry time.
+           -> a           -- ^ Request to presign.
+           -> m ByteString
+presignURL ts ex x = do
+    a <- view envAuth
+    r <- view envRegion
+    Sign.presignURL a r ts ex x
 
-    go (AwaitF s w (request -> x) k) = do
-        e <- view environment
-        r <- lift . f =<< waiter e w x (perform e s x)
-        k (snd r)
+-- | Presign an HTTP request that is valid from the specified time until the
+-- number of seconds expiry has elapsed.
+--
+-- /See:/ 'presignWith'
+presign :: ( MonadIO m
+           , MonadReader r m
+           , HasEnv r
+           , AWSPresigner (Sg (Sv a))
+           , AWSRequest a
+           )
+        => UTCTime     -- ^ Signing time.
+        -> Seconds     -- ^ Expiry time.
+        -> a           -- ^ Request to presign.
+        -> m ClientRequest
+presign = presignWith id
 
-    tryT m = either (Left . TransportError) Right <$> try m
+-- | A variant of 'presign' that allows specifying the 'Service' definition
+-- used to configure the request.
+presignWith :: ( MonadIO m
+               , MonadReader r m
+               , HasEnv r
+               , AWSPresigner (Sg s)
+               , AWSRequest a
+               )
+            => (Service (Sv a) -> Service s) -- ^ Function to modify the service configuration.
+            -> UTCTime                       -- ^ Signing time.
+            -> Seconds                       -- ^ Expiry time.
+            -> a                             -- ^ Request to presign.
+            -> m ClientRequest
+presignWith f ts ex x = do
+    a <- view envAuth
+    g <- view envRegion
+    Sign.presignWith f a g ts ex x
 
-innerAWST :: (Monad m, HasEnv r)
-          => (Command (ReaderT Env m a) -> ReaderT Env m a)
-          -> r
-          -> AWST m a
-          -> m a
-innerAWST f e (AWST m) = runReaderT (f `iterT` m) (e ^. environment)
+-- | Test whether the underlying host is running on EC2.
+-- This is memoised and any external check occurs for the first invocation only.
+isEC2 :: (MonadIO m, MonadReader r m, HasEnv r) => m Bool
+isEC2 = do
+    ref <- view envEC2
+    mp  <- liftIO (readIORef ref)
+    case mp of
+        Just p  -> return p
+        Nothing -> do
+            m  <- view envManager
+            !p <- EC2.isEC2 m
+            liftIO (atomicWriteIORef ref (Just p))
+            return p
 
-hoistAWST :: (Monad m, Monad n)
-          => (forall a. m a -> n a)
-          -> AWST m b
-          -> AWST n b
-hoistAWST nat = AWST . hoistFT (hoist nat) . unAWST
+-- | Retrieve the specified 'Dynamic' data.
+--
+-- Throws 'HttpException'.
+dynamic :: (MonadIO m, MonadThrow m, MonadReader r m, HasEnv r)
+        => EC2.Dynamic
+        -> m ByteString
+dynamic d = view envManager >>= flip EC2.dynamic d
+
+-- | Retrieve the specified 'Metadata'.
+--
+-- Throws 'HttpException'.
+metadata :: (MonadIO m, MonadThrow m, MonadReader r m, HasEnv r)
+         => EC2.Metadata
+         -> m ByteString
+metadata m = view envManager >>= flip EC2.metadata m
+
+-- | Retrieve the user data. Returns 'Nothing' if no user data is assigned
+-- to the instance.
+--
+-- Throws 'HttpException'.
+userdata :: (MonadIO m, MonadCatch m, MonadReader r m, HasEnv r)
+         => m (Maybe ByteString)
+userdata = view envManager >>= EC2.userdata
 
 hoistError :: MonadThrow m => Either Error a -> m a
 hoistError = either (throwingM _Error) return
diff --git a/src/Network/AWS.hs b/src/Network/AWS.hs
--- a/src/Network/AWS.hs
+++ b/src/Network/AWS.hs
@@ -121,7 +121,6 @@
     , newLogger
 
     -- * Re-exported Types
-    , AWST.Command
     , RqBody
     , RsBody
     , module Network.AWS.Types
@@ -133,43 +132,40 @@
     ) where
 
 import           Control.Applicative
-import           Control.Monad.Catch             (MonadCatch)
-import           Control.Monad.Morph             (hoist)
-import qualified Control.Monad.RWS.Lazy          as LRW
-import qualified Control.Monad.RWS.Strict        as RW
-import qualified Control.Monad.State.Lazy        as LS
-import qualified Control.Monad.State.Strict      as S
-import           Control.Monad.Trans.AWS         (AWST)
-import qualified Control.Monad.Trans.AWS         as AWST
-import           Control.Monad.Trans.Class       (lift)
-import           Control.Monad.Trans.Cont        (ContT)
-import           Control.Monad.Trans.Except      (ExceptT)
-import           Control.Monad.Trans.Free        (FreeT)
-import           Control.Monad.Trans.Free.Church (FT)
-import           Control.Monad.Trans.Identity    (IdentityT)
-import           Control.Monad.Trans.Iter        (IterT)
-import           Control.Monad.Trans.List        (ListT)
-import           Control.Monad.Trans.Maybe       (MaybeT)
-import           Control.Monad.Trans.Reader      (ReaderT)
+import           Control.Monad.Catch          (MonadCatch)
+import           Control.Monad.Morph          (hoist)
+import qualified Control.Monad.RWS.Lazy       as LRW
+import qualified Control.Monad.RWS.Strict     as RW
+import qualified Control.Monad.State.Lazy     as LS
+import qualified Control.Monad.State.Strict   as S
+import           Control.Monad.Trans.AWS      (AWST)
+import qualified Control.Monad.Trans.AWS      as AWST
+import           Control.Monad.Trans.Class    (lift)
+import           Control.Monad.Trans.Cont     (ContT)
+import           Control.Monad.Trans.Except   (ExceptT)
+import           Control.Monad.Trans.Identity (IdentityT)
+import           Control.Monad.Trans.List     (ListT)
+import           Control.Monad.Trans.Maybe    (MaybeT)
+import           Control.Monad.Trans.Reader   (ReaderT)
 import           Control.Monad.Trans.Resource
-import qualified Control.Monad.Writer.Lazy       as LW
-import qualified Control.Monad.Writer.Strict     as W
-import           Data.Conduit                    (Source)
+import qualified Control.Monad.Writer.Lazy    as LW
+import qualified Control.Monad.Writer.Strict  as W
+import           Data.Conduit                 (Source)
 import           Data.Monoid
 import           Network.AWS.Auth
-import qualified Network.AWS.EC2.Metadata        as EC2
-import           Network.AWS.Env                 (Env, HasEnv (..), newEnv)
+import qualified Network.AWS.EC2.Metadata     as EC2
+import           Network.AWS.Env              (Env, HasEnv (..), newEnv)
 import           Network.AWS.Internal.Body
 import           Network.AWS.Internal.Logger
-import           Network.AWS.Pager               (AWSPager)
+import           Network.AWS.Pager            (AWSPager)
 import           Network.AWS.Prelude
-import           Network.AWS.Types               hiding (LogLevel (..))
-import           Network.AWS.Waiter              (Wait)
+import           Network.AWS.Types            hiding (LogLevel (..))
+import           Network.AWS.Waiter           (Wait)
 
 import           Prelude
 
 -- | A specialisation of the 'AWST' transformer.
-type AWS = AWST IO
+type AWS = AWST (ResourceT IO)
 
 -- | Monads in which 'AWS' actions may be embedded.
 class (Functor m, Applicative m, Monad m) => MonadAWS m where
@@ -187,8 +183,6 @@
 instance MonadAWS m => MonadAWS (ReaderT   r m) where liftAWS = lift . liftAWS
 instance MonadAWS m => MonadAWS (S.StateT  s m) where liftAWS = lift . liftAWS
 instance MonadAWS m => MonadAWS (LS.StateT s m) where liftAWS = lift . liftAWS
-instance MonadAWS m => MonadAWS (IterT       m) where liftAWS = lift . liftAWS
-instance MonadAWS m => MonadAWS (FT        f m) where liftAWS = lift . liftAWS
 
 instance (Monoid w, MonadAWS m) => MonadAWS (W.WriterT w m) where
     liftAWS = lift . liftAWS
@@ -202,22 +196,15 @@
 instance (Monoid w, MonadAWS m) => MonadAWS (LRW.RWST r w s m) where
     liftAWS = lift . liftAWS
 
-instance (Functor f, MonadAWS m) => MonadAWS (FreeT f m) where
-    liftAWS = lift . liftAWS
-
--- FIXME: verify the use of withInternalState to create a ResourceT here
-
 -- | Run the 'AWS' monad. Any outstanding HTTP responses' 'ResumableSource' will
 -- be closed when the 'ResourceT' computation is unwrapped with 'runResourceT'.
 --
 -- Throws 'Error', which will include 'HTTPExceptions', serialisation errors,
 -- or any particular errors returned by the respective AWS service.
 --
--- /See:/ 'runAWST', 'runResourceT'.
-runAWS :: (MonadCatch m, MonadResource m, HasEnv r) => r -> AWS a -> m a
-runAWS e = liftResourceT
-    . AWST.runAWST e
-    . AWST.hoistAWST (withInternalState . const)
+-- /See:/ 'AWST.runAWST', 'runResourceT'.
+runAWS :: (MonadResource m, HasEnv r) => r -> AWS a -> m a
+runAWS e = liftResourceT . AWST.runAWST e
 
 -- | Scope an action within the specific 'Region'.
 within :: MonadAWS m => Region -> AWS a -> m a
@@ -249,7 +236,7 @@
 -- is fulfilled.
 --
 -- /See:/ 'AWST.awaitWith'
-await :: (MonadAWS m, AWSRequest a) => Wait a -> a -> m (Rs a)
+await :: (MonadAWS m, AWSRequest a) => Wait a -> a -> m ()
 await w = liftAWS . AWST.await w
 
 -- | Presign an URL that is valid from the specified time until the
diff --git a/src/Network/AWS/Auth.hs b/src/Network/AWS/Auth.hs
--- a/src/Network/AWS/Auth.hs
+++ b/src/Network/AWS/Auth.hs
@@ -67,6 +67,7 @@
 import           Control.Monad.IO.Class
 import qualified Data.ByteString.Char8      as BS8
 import qualified Data.ByteString.Lazy.Char8 as LBS8
+import           Data.Char                  (isSpace)
 import qualified Data.Ini                   as INI
 import           Data.IORef
 import           Data.Monoid
@@ -122,10 +123,15 @@
 --
 -- /Note:/ This does not match the default AWS SDK location of
 -- @%USERPROFILE%\.aws\credentials@ on Windows. (Sorry.)
-credFile :: MonadIO m => m FilePath
-credFile = (<> "/.aws/credentials") `liftM` liftIO getHomeDirectory
--- TODO: probably should be using System.FilePath above.
+credFile :: (MonadCatch m, MonadIO m) => m FilePath
+credFile = catching_ _IOException dir err
+  where
+    dir = (++ p) `liftM` liftIO getHomeDirectory
+    err = throwM $ MissingFileError ("$HOME" ++ p)
 
+    -- TODO: probably should be using System.FilePath above.
+    p = "/.aws/credentials"
+
 {- $credentials
 'getAuth' is implemented using the following @from*@-styled functions below.
 Both 'fromKeys' and 'fromSession' can be used directly to avoid the 'MonadIO'
@@ -265,7 +271,8 @@
 
 -- | Retrieve authentication information via the specified 'Credentials' mechanism.
 --
--- Throws 'AuthError' when environment variables or IAM profiles cannot be read.
+-- Throws 'AuthError' when environment variables or IAM profiles cannot be read,
+-- and credentials files are invalid or cannot be found.
 getAuth :: (Applicative m, MonadIO m, MonadCatch m)
         => Manager
         -> Credentials
@@ -284,7 +291,10 @@
             catching _MissingFileError fromFile $ \f -> do
                 -- proceed, missing credentials file
                 p <- isEC2 m
-                unless p $ throwingM _MissingFileError f
+                unless p $
+                    -- not an EC2 instance, rethrow the previous error.
+                    throwingM _MissingFileError f
+                 -- proceed, check EC2 metadata for IAM information.
                 fromProfile m
 
 -- | Retrieve access key, secret key, and a session token from the default
@@ -343,7 +353,7 @@
 fromFilePath n f = do
     p <- liftIO (doesFileExist f)
     unless p $ throwM (MissingFileError f)
-    i <- either (throwM . invalidErr) return =<< liftIO (INI.readIniFile f)
+    i <- liftIO (INI.readIniFile f) >>= either (invalidErr Nothing) return
     fmap Auth $ AuthEnv
         <$> (req credAccessKey i    <&> AccessKey)
         <*> (req credSecretKey i    <&> SecretKey)
@@ -351,17 +361,22 @@
         <*> pure Nothing
   where
     req k i =
-        either (throwM . invalidErr)
-               (return . Text.encodeUtf8)
-               (INI.lookupValue n k i)
+        case INI.lookupValue n k i of
+            Left  e         -> invalidErr (Just k) e
+            Right x
+                | blank x   -> invalidErr (Just k) "cannot be a blank string."
+                | otherwise -> return (Text.encodeUtf8 x)
 
     opt k i = return $
-        either (const Nothing)
-               (Just . Text.encodeUtf8)
-               (INI.lookupValue n k i)
+        case INI.lookupValue n k i of
+            Left  _ -> Nothing
+            Right x -> Just (Text.encodeUtf8 x)
 
-    invalidErr :: String -> AuthError
-    invalidErr = InvalidFileError . Text.pack
+    invalidErr Nothing  e = throwM $ InvalidFileError (Text.pack e)
+    invalidErr (Just k) e = throwM $ InvalidFileError
+        (Text.pack f <> ", key " <> k <> " " <> Text.pack e)
+
+    blank x = Text.null x || Text.all isSpace x
 
 -- | Retrieve the default IAM Profile from the local EC2 instance-data.
 --
diff --git a/src/Network/AWS/EC2/Metadata.hs b/src/Network/AWS/EC2/Metadata.hs
--- a/src/Network/AWS/EC2/Metadata.hs
+++ b/src/Network/AWS/EC2/Metadata.hs
@@ -18,11 +18,6 @@
 --
 -- It is intended to be used when you need to make metadata calls prior to
 -- initialisation of the 'Network.AWS.Env.Env'.
--- If you wish to retrieve instance metadata during normal operations
--- and are using either the 'Network.AWS.AWS' or 'Control.Monad.Trans.AWS.AWST'
--- monads, then prefer one of the 'Control.Monad.Trans.AWS.metadata' related
--- functions available there, as the functions in this module do not use the
--- underlying 'MonadFree' 'Network.AWS.Free.Command' DSL.
 module Network.AWS.EC2.Metadata
     (
     -- * EC2 Instance Check
diff --git a/src/Network/AWS/Free.hs b/src/Network/AWS/Free.hs
deleted file mode 100644
--- a/src/Network/AWS/Free.hs
+++ /dev/null
@@ -1,201 +0,0 @@
-{-# LANGUAGE BangPatterns      #-}
-{-# LANGUAGE CPP               #-}
-{-# LANGUAGE FlexibleContexts  #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GADTs             #-}
-{-# LANGUAGE LambdaCase        #-}
-{-# LANGUAGE RankNTypes        #-}
-
--- |
--- Module      : Network.AWS.Free
--- Copyright   : (c) 2013-2015 Brendan Hay
--- License     : Mozilla Public License, v. 2.0.
--- Maintainer  : Brendan Hay <brendan.g.hay@gmail.com>
--- Stability   : provisional
--- Portability : non-portable (GHC extensions)
---
--- Defines the core AST, logic and interpreters for AWS behaviour.
-module Network.AWS.Free where
-
-import           Control.Applicative
-import           Control.Monad.Reader
-import           Control.Monad.Trans.Free.Church
-import           Data.Conduit                    (Source, yield)
-import           Network.AWS.EC2.Metadata        (Dynamic, Metadata)
-import           Network.AWS.Pager
-import           Network.AWS.Prelude
-import           Network.AWS.Request             (requestURL)
-import           Network.AWS.Types
-import           Network.AWS.Waiter
-#if MIN_VERSION_free(4,12,0)
-#else
-import           Control.Monad.Catch
-import           Control.Monad.Trans.Free        (FreeT (..))
-#endif
-
-import           Prelude
-
-data Command r where
-    CheckF ::             (Bool             -> r) -> Command r
-    DynF   :: Dynamic  -> (ByteString       -> r) -> Command r
-    MetaF  :: Metadata -> (ByteString       -> r) -> Command r
-    UserF  ::             (Maybe ByteString -> r) -> Command r
-
-    SignF  :: (AWSPresigner (Sg s), AWSRequest a)
-           => Service s
-           -> UTCTime
-           -> Seconds
-           -> a
-           -> (ClientRequest -> r)
-           -> Command r
-
-    SendF  :: (AWSSigner (Sg s), AWSRequest a)
-           => Service s
-           -> a
-           -> (Rs a -> r)
-           -> Command r
-
-    AwaitF :: (AWSSigner (Sg s), AWSRequest a)
-           => Service s
-           -> Wait a
-           -> a
-           -> (Rs a -> r)
-           -> Command r
-
-instance Functor Command where
-    fmap f = \case
-        CheckF         k -> CheckF         (fmap f k)
-        DynF         x k -> DynF         x (fmap f k)
-        MetaF        x k -> MetaF        x (fmap f k)
-        UserF          k -> UserF          (fmap f k)
-        SignF  s t e x k -> SignF  s t e x (fmap f k)
-        SendF  s     x k -> SendF  s     x (fmap f k)
-        AwaitF s w   x k -> AwaitF s w   x (fmap f k)
-
-#if MIN_VERSION_free(4,12,0)
-#else
-instance MonadThrow m => MonadThrow (FreeT Command m) where
-    throwM = lift . throwM
-
-instance MonadCatch m => MonadCatch (FreeT Command m) where
-    catch (FreeT m) f = FreeT $
-        liftM (fmap (`catch` f)) m `catch` (runFreeT . f)
-
-instance MonadThrow m => MonadThrow (FT Command m) where
-    throwM = lift . throwM
-
-instance MonadCatch m => MonadCatch (FT Command m) where
-    catch m f = toFT $ fromFT m `catch` (fromFT . f)
-#endif
-
--- | Send a request, returning the associated response if successful.
---
--- /See:/ 'sendWith'
-send :: (MonadFree Command m, AWSRequest a)
-     => a
-     -> m (Rs a)
-send = sendWith id
-
--- | A variant of 'send' that allows modifying the default 'Service' definition
--- used to configure the request.
-sendWith :: (MonadFree Command m, AWSSigner (Sg s), AWSRequest a)
-         => (Service (Sv a) -> Service s) -- ^ Modify the default service configuration.
-         -> a                             -- ^ Request.
-         -> m (Rs a)
-sendWith f x = liftF (SendF (f (serviceOf x)) x id)
-
--- | Repeatedly send a request, automatically setting markers and
--- paginating over multiple responses while available.
---
--- /See:/ 'paginateWith'
-paginate :: (MonadFree Command m, AWSPager a)
-         => a
-         -> Source m (Rs a)
-paginate = paginateWith id
-
--- | A variant of 'paginate' that allows modifying the default 'Service' definition
--- used to configure the request.
-paginateWith :: (MonadFree Command m, AWSSigner (Sg s), AWSPager a)
-             => (Service (Sv a) -> Service s) -- ^ Modify the default service configuration.
-             -> a                             -- ^ Initial request.
-             -> Source m (Rs a)
-paginateWith f rq = go rq
-  where
-    go !x = do
-        !y <- lift $ liftF (SendF s x id)
-        yield y
-        maybe (pure ())
-              go
-              (page x y)
-
-    !s = f (serviceOf rq)
-
--- | Poll the API with the supplied request until a specific 'Wait' condition
--- is fulfilled.
---
--- /See:/ 'awaitWith'
-await :: (MonadFree Command m, AWSRequest a)
-      => Wait a
-      -> a
-      -> m (Rs a)
-await = awaitWith id
-
--- | A variant of 'await' that allows modifying the default 'Service' definition
--- used to configure the request.
-awaitWith :: (MonadFree Command m, AWSSigner (Sg s), AWSRequest a)
-          => (Service (Sv a) -> Service s) -- ^ Modify the default service configuration.
-          -> Wait a                        -- ^ Polling, error and acceptance criteria.
-          -> a                             -- ^ Request to poll with.
-          -> m (Rs a)
-awaitWith f w x = liftF (AwaitF (f (serviceOf x)) w x id)
-
--- | Presign an URL that is valid from the specified time until the
--- number of seconds expiry has elapsed.
---
--- /See:/ 'presign', 'presignWith'
-presignURL :: (MonadFree Command m, AWSPresigner (Sg (Sv a)), AWSRequest a)
-           => UTCTime     -- ^ Signing time.
-           -> Seconds     -- ^ Expiry time.
-           -> a           -- ^ Request to presign.
-           -> m ByteString
-presignURL ts ex = liftM requestURL . presign ts ex
-
--- | Presign an HTTP request that is valid from the specified time until the
--- number of seconds expiry has elapsed.
---
--- /See:/ 'presignWith'
-presign :: (MonadFree Command m, AWSPresigner (Sg (Sv a)), AWSRequest a)
-        => UTCTime     -- ^ Signing time.
-        -> Seconds     -- ^ Expiry time.
-        -> a           -- ^ Request to presign.
-        -> m ClientRequest
-presign = presignWith id
-
--- | A variant of 'presign' that allows specifying the 'Service' definition
--- used to configure the request.
-presignWith :: (MonadFree Command m, AWSPresigner (Sg s), AWSRequest a)
-            => (Service (Sv a) -> Service s) -- ^ Function to modify the service configuration.
-            -> UTCTime                       -- ^ Signing time.
-            -> Seconds                       -- ^ Expiry time.
-            -> a                             -- ^ Request to presign.
-            -> m ClientRequest
-presignWith f ts ex x = liftF (SignF (f (serviceOf x)) ts ex x id)
-
--- | Test whether the underlying host is running on EC2.
--- For 'IO' based interpretations of 'MonadFree' 'Command', this is memoised and
--- any external check occurs for the first call only.
-isEC2 :: MonadFree Command m => m Bool
-isEC2 = liftF (CheckF id)
-
--- | Retrieve the specified 'Dynamic' data.
-dynamic :: MonadFree Command m => Dynamic -> m ByteString
-dynamic d = liftF (DynF d id)
-
--- | Retrieve the specified 'Metadata'.
-metadata :: MonadFree Command m => Metadata -> m ByteString
-metadata m = liftF (MetaF m id)
-
--- | Retrieve the user data. Returns 'Nothing' if no user data is assigned
--- to the instance.
-userdata :: MonadFree Command m => m (Maybe ByteString)
-userdata = liftF (UserF id)
diff --git a/src/Network/AWS/Internal/HTTP.hs b/src/Network/AWS/Internal/HTTP.hs
--- a/src/Network/AWS/Internal/HTTP.hs
+++ b/src/Network/AWS/Internal/HTTP.hs
@@ -101,7 +101,7 @@
         . mconcat
         . intersperse " "
         $ [ "[Retry " <> build x <> "]"
-          , " after "
+          , "after"
           , build (n + 1)
           , "attempts."
           ]
@@ -113,16 +113,22 @@
        -> Wait a
        -> Request a
        -> m (Either Error (Response a))
-       -> m (Either Error (Response a))
-waiter Env{..} w@Wait{..} rq = retrying policy check
+       -> m (Maybe Error)
+waiter Env{..} w@Wait{..} rq f = retrying policy check wait >>= exit
   where
     policy = limitRetries _waitAttempts
           <> constantDelay (microseconds _waitDelay)
 
-    check n rs = do
-        let a = fromMaybe AcceptRetry (accept w rq rs)
-        msg n a >> return (retry a)
+    wait = do
+        e <- f
+        return (fromMaybe AcceptRetry (accept w rq e), e)
 
+    exit (AcceptSuccess, _)      = return Nothing
+    exit (_,             Left e) = return (Just e)
+    exit (_,             _)      = return Nothing
+
+    check n (a, _) = msg n a >> return (retry a)
+
     retry AcceptSuccess = False
     retry AcceptFailure = False
     retry AcceptRetry   = True
@@ -132,7 +138,7 @@
         . intersperse " "
         $ [ "[Await " <> build _waitName <> "]"
           , build a
-          , " after "
+          , "after"
           , build (n + 1)
           , "attempts."
           ]
diff --git a/src/Network/AWS/Presign.hs b/src/Network/AWS/Presign.hs
--- a/src/Network/AWS/Presign.hs
+++ b/src/Network/AWS/Presign.hs
@@ -13,11 +13,6 @@
 --
 -- It is intended for use directly with "Network.AWS.Auth" when only presigning
 -- and no other AWS actions are required.
--- If you wish to presign requests and are using either the 'Network.AWS.AWS'
--- or 'Control.Monad.Trans.AWS.AWST' monads, then prefer one of the relevant
--- 'Control.Monad.Trans.AWS.presign'ing functions available there, as the
--- functions in this module do not use the underlying 'MonadFree'
--- 'Network.AWS.Free.Command' DSL.
 module Network.AWS.Presign where
 
 import           Control.Lens
