diff --git a/source/AirGQL/GraphQL.hs b/source/AirGQL/GraphQL.hs
index 6b2a4ae..2d7abb7 100644
--- a/source/AirGQL/GraphQL.hs
+++ b/source/AirGQL/GraphQL.hs
@@ -102,8 +102,7 @@ import AirGQL.Types.SchemaConf (
   SchemaConf (accessMode, maxRowsPerTable, pragmaConf),
  )
 import AirGQL.Types.Utils (encodeToText)
-import AirGQL.Utils (colToFileUrl, collectErrorList, quoteKeyword, quoteText)
-import Data.Either.Extra qualified as Either
+import AirGQL.Utils (colToFileUrl, quoteKeyword, quoteText)
 import Data.List qualified as List
 import Language.GraphQL.Class (FromGraphQL (fromGraphQL))
 
@@ -385,7 +384,19 @@ gqlValueToSQLData = \case
   Object obj -> SQLText $ show obj
 
 
-rowToGraphQL :: Text -> TableEntry -> [SQLData] -> Either [(Text, Text)] Value
+-- The way Airsequel works at the moment is by generating one big GQL object at
+-- the root-most resolver, and then having child resolvers pick up the sections
+-- they need.
+--
+-- One issue with this way of doing things is that we don't have a way to
+-- generate location-specific errors, thus we used to simply error out at the
+-- first issue, without returning partial results.
+--
+-- The "hack" I came up to fix this, is to return a failed field named "foo" as
+-- a field named "__error_foo" containing the text of the error. The child
+-- resolvers can later pick up this error, and fail themselves only, thus
+-- returning partial results.
+rowToGraphQL :: Text -> TableEntry -> [SQLData] -> Value
 rowToGraphQL dbId table row =
   let
     buildMetadataJson :: Text -> Text -> Text
@@ -393,80 +404,51 @@ rowToGraphQL dbId table row =
       object ["url" .= colToFileUrl dbId table.name colName rowid]
         & encodeToText
 
-    parseSqlData :: (ColumnEntry, SQLData) -> Either (Text, Text) (Text, Value)
+    parseSqlData :: (ColumnEntry, SQLData) -> (Text, Value)
     parseSqlData (colEntry, colVal) =
       if "BLOB" `T.isPrefixOf` colEntry.datatype
         then
-          pure
-            ( colEntry.column_name_gql
-            , case colVal of
-                SQLNull -> Null
-                SQLInteger id ->
-                  String $
-                    buildMetadataJson colEntry.column_name (show id)
-                SQLText id ->
-                  String $
-                    buildMetadataJson colEntry.column_name id
-                _ -> Null
-            )
+          ( colEntry.column_name_gql
+          , case colVal of
+              SQLNull -> Null
+              SQLInteger id ->
+                String $
+                  buildMetadataJson colEntry.column_name (show id)
+              SQLText id ->
+                String $
+                  buildMetadataJson colEntry.column_name id
+              _ -> Null
+          )
         else case sqlDataToGQLValue colEntry.datatype colVal of
           Left err ->
-            Left
-              (colEntry.column_name_gql, err)
+            ( "__error_" <> colEntry.column_name_gql
+            , String err
+            )
           Right gqlData ->
-            Right
-              ( colEntry.column_name_gql
-              , case colEntry.datatype of
-                  -- Coerce value to nullable String
-                  -- if no datatype is set.
-                  -- This happens for columns in views.
-                  "" -> gqlValueToNullableString gqlData
-                  _ -> gqlData
-              )
+            ( colEntry.column_name_gql
+            , case colEntry.datatype of
+                -- Coerce value to nullable String
+                -- if no datatype is set.
+                -- This happens for columns in views.
+                "" -> gqlValueToNullableString gqlData
+                _ -> gqlData
+            )
   in
     -- => [(ColumnEntry, SQLData)]
     P.zip table.columns row
-      -- => [Either (Text, Text) (Text, Value)]
+      -- => [(Text, Value)]
       <&> parseSqlData
-      -- => Either [(Text, Text)] (Text, Value)
-      & collectErrorList
-      -- => Either [(Text, Text)] (HashMap Text Value)
-      <&> HashMap.fromList
-      -- => Either [(Text, Text)] Value
-      <&> Object
+      -- => HashMap Text Value
+      & HashMap.fromList
+      -- => Value
+      & Object
 
 
-rowsToGraphQL
-  :: Text
-  -> TableEntry
-  -> [[SQLData]]
-  -> Either [(Text, Text)] Value
+rowsToGraphQL :: Text -> TableEntry -> [[SQLData]] -> Value
 rowsToGraphQL dbId table updatedRows =
   updatedRows
-    -- => [Either [(Text, Text)] Value]
     <&> rowToGraphQL dbId table
-    -- => Either [[(Text, Text)]] [Value]
-    & collectErrorList
-    -- => Either [(Text, Text)] [Value]
-    & Either.mapLeft P.join
-    -- => Either [(Text, Text)] Value
-    <&> List
-
-
--- | Formats errors from `row(s)ToGraphQL` and throws them.
-colErrorsToUserError :: forall m a. (MonadIO m) => Either [(Text, Text)] a -> m a
-colErrorsToUserError = \case
-  Right v -> pure v
-  Left errors ->
-    let
-      errorLines =
-        errors
-          <&> \(column, err) -> "On column " <> show column <> ": " <> err
-    in
-      P.throwIO $
-        userError $
-          T.unpack $
-            "Multiple errors occurred:\n" <> P.unlines errorLines
+    & List
 
 
 tryGetArg
@@ -742,7 +724,7 @@ queryType connection accessMode dbId tables = do
               orderElements
               paginationMb
 
-      colErrorsToUserError $ rowsToGraphQL dbId table rows
+      pure $ rowsToGraphQL dbId table rows
 
     getDbEntriesByPK :: TableEntry -> Out.Resolve IO
     getDbEntriesByPK tableEntry = do
@@ -764,7 +746,7 @@ queryType connection accessMode dbId tables = do
       case P.head queryResult of
         Nothing -> pure Null
         Just row ->
-          colErrorsToUserError $
+          pure $
             rowToGraphQL
               dbId
               tableEntry
@@ -835,9 +817,7 @@ mutationType connection maxRowsPerTable accessMode dbId tables = do
 
     mutationResponse :: TableEntry -> Int -> [[SQLData]] -> IO Value
     mutationResponse table numChanges rows = do
-      returning <-
-        colErrorsToUserError $
-          rowsToGraphQL dbId table rows
+      let returning = rowsToGraphQL dbId table rows
 
       pure $
         Object $
@@ -848,11 +828,9 @@ mutationType connection maxRowsPerTable accessMode dbId tables = do
 
     mutationByPKResponse :: TableEntry -> Int -> Maybe [SQLData] -> IO Value
     mutationByPKResponse table numChanges mbRow = do
-      returning <- case mbRow of
-        Nothing -> pure Null
-        Just row ->
-          colErrorsToUserError $
-            rowToGraphQL dbId table row
+      let returning = case mbRow of
+            Nothing -> Null
+            Just row -> rowToGraphQL dbId table row
 
       pure $
         Object $
diff --git a/source/AirGQL/Introspection/Resolver.hs b/source/AirGQL/Introspection/Resolver.hs
index 017d431..95aa6bf 100644
--- a/source/AirGQL/Introspection/Resolver.hs
+++ b/source/AirGQL/Introspection/Resolver.hs
@@ -1,3 +1,6 @@
+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
+
+{-# HLINT ignore "Replace case with maybe" #-}
 module AirGQL.Introspection.Resolver (
   makeType,
   makeConstField,
@@ -8,9 +11,9 @@ import Protolude (
   Either (Left),
   IO,
   Int,
+  Maybe (Just, Nothing),
   MonadReader (ask),
   Text,
-  fromMaybe,
   pure,
   show,
   ($),
@@ -23,7 +26,11 @@ import Protolude (
 import Protolude qualified as P
 
 import AirGQL.Introspection.Types qualified as IType
+import Control.Exception qualified as Exception
 import Data.HashMap.Strict qualified as HashMap
+import Data.Text qualified as T
+import GHC.IO.Exception (userError)
+import Language.GraphQL.Error (ResolverException (ResolverException))
 import Language.GraphQL.Type qualified as Type
 import Language.GraphQL.Type.In qualified as In
 import Language.GraphQL.Type.Out qualified as Out
@@ -32,6 +39,14 @@ import Language.GraphQL.Type.Out qualified as Out
 type Result = Either Text
 
 
+throwResolverError :: Text -> m a
+throwResolverError err =
+  Exception.throw $
+    ResolverException $
+      userError $
+        T.unpack err
+
+
 {-| Turns a type descriptor into a graphql output type, erroring out on input
 types. Child resolvers look up their respective fields in the value produced by
 their parent.
@@ -123,18 +138,23 @@ makeType =
         let defaultValue =
               if Out.isNonNullType ty
                 then
-                  Type.String $
+                  throwResolverError $
                     "Error: field '"
                       <> field.name
                       <> "' not found "
-                else Type.Null
+                else pure Type.Null
 
         case context.values of
-          Type.Object obj ->
-            pure $
-              fromMaybe defaultValue $
-                HashMap.lookup field.name obj
-          _ -> pure defaultValue
+          Type.Object obj -> do
+            let errorValue = HashMap.lookup ("__error_" <> field.name) obj
+            P.for_ errorValue $ \case
+              Type.String err -> throwResolverError err
+              _ -> pure ()
+
+            case HashMap.lookup field.name obj of
+              Just value -> pure value
+              Nothing -> defaultValue
+          _ -> defaultValue
   in
     makeTypeWithDepth 0
 
diff --git a/tests/Tests/QuerySpec.hs b/tests/Tests/QuerySpec.hs
index 9850a39..14d0eef 100644
--- a/tests/Tests/QuerySpec.hs
+++ b/tests/Tests/QuerySpec.hs
@@ -820,15 +820,28 @@ main = void $ do
             rmSpaces
               [raw|
                   {
-                    "data": null,
+                    "data": {
+                      "test": [{
+                        "alsobig": null,
+                        "big": null
+                      }]
+                    },
                     "errors": [{
                       "locations": [{
-                        "column": 3,
-                        "line": 2
+                        "column": 5,
+                        "line": 3
                       }],
                       "message":
-                        "user error (Multiple errors occurred:\nOn column \"big\": Integer 8000000000 would overflow. This happens because SQLite uses 64-bit ints, but GraphQL uses 32-bit ints. Use a Number (64-bit float) or Text column instead.\nOn column \"alsobig\": Integer 9000000000 would overflow. This happens because SQLite uses 64-bit ints, but GraphQL uses 32-bit ints. Use a Number (64-bit float) or Text column instead.\n)",
-                      "path": ["test"]
+                        "user error (Integer 8000000000 would overflow. This happens because SQLite uses 64-bit ints, but GraphQL uses 32-bit ints. Use a Number (64-bit float) or Text column instead.)",
+                      "path": ["test", 0, "big"]
+                    }, {
+                      "locations": [{
+                        "column": 5,
+                        "line": 4
+                      }],
+                      "message":
+                        "user error (Integer 9000000000 would overflow. This happens because SQLite uses 64-bit ints, but GraphQL uses 32-bit ints. Use a Number (64-bit float) or Text column instead.)",
+                      "path": ["test", 0, "alsobig"]
                     }]
                   }
                 |]