diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,19 @@
 ## Changelog
+### 0.9.0
+
+- Added cabal flag to allow fully safe garbage collection: Lua garbage
+  collection can occur in most of the API functions, even in those usually not
+  calling back into haskell and hence marked as optimizable. The effect of this
+  is that finalizers which call Haskell functions will cause the program to
+  hang. A new flag `allow-unsafe-gc` is introduced and enabled by default.
+  Disabling this flag will mark more C API functions as potentially calling back
+  into Haskell. This has a serious performance impact.
+- `FromLuaStack` and `ToLuaStack` instances for lazy ByteStrings are added.
+- None-string error messages are handled properly: Lua allows error messages to
+  be of any type, but the haskell error handlers expected string values. Tables,
+  booleans, and other non-string values are now handled as well and converted to
+  strings.
+
 ### 0.8.0
 
 - Use newtype definitions instead of type aliases for LuaNumber and LuaInteger.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -14,16 +14,47 @@
 [Hackage]: http://img.shields.io/hackage/v/hslua.svg
 
 
-Using a different lua version
------------------------------
+Build flags
+-----------
 
-To use system-wide installed Lua/LuaJIT when linking hslua as a dependency,
+The following cabal build flags are supported:
+
+- `system-lua`: Use the locally installed Lua version instead of the version
+  shipped as part of HsLua.
+
+- `use-pkgconfig`: Use `pkg-config` to discover library and include paths. This
+  is used only when the `system-lua` flag is set or implied.
+
+- `lua501`: Build against Lua 5.1; this implies the flag `system-lua` as well.
+
+- `lua502`: Build against Lua 5.2; this implies the flag `system-lua` as well.
+
+- `luajit`: Build against LuaJIT; this implies the flag `system-lua` as well.
+
+- `allow-unsafe-gc`: Allow optimizations which make Lua's garbage collection
+  potentially unsafe; haskell finalizers must be handled with extreme care. This
+  is *enabled* per default, as this is rarely a problem in practice.
+
+- `apicheck`: Compile Lua with its API checks enabled.
+
+- `lua_32bits`: Compile Lua for a 32-bits system (e.g., i386, PowerPC G4).
+
+
+### Example: using a different lua version
+
+To use a system-wide installed Lua/LuaJIT when linking hslua as a dependency,
 build/install your package using `--constraint="hslua +system-lua"` or for
-LuaJIT: `--constraint="hslua +system-lua +luajit"`. For example, you can install
-Pandoc with hslua that uses system-wide LuaJIT like this:
+LuaJIT: `--constraint="hslua +luajit"`. For example, you can install Pandoc with
+hslua that uses system-wide LuaJIT like this:
 
 ``` sh
 cabal install pandoc --constraint="hslua +system-lua +luajit"
+```
+
+or with stack:
+
+``` sh
+stack install pandoc --flag=hslua:luajit
 ```
 
 
diff --git a/hslua.cabal b/hslua.cabal
--- a/hslua.cabal
+++ b/hslua.cabal
@@ -1,5 +1,5 @@
 name:                   hslua
-version:                0.8.0
+version:                0.9.0
 stability:              beta
 cabal-version:          >= 1.8
 license:                MIT
@@ -47,6 +47,12 @@
   description:          Compile Lua with -DLUA_32BITS
   default:              False
 
+flag allow-unsafe-gc
+  description:          Allow optimizations which make Lua's garbage collection
+                        potentially unsafe; haskell finalizers must be handled
+                        with extreme care.
+  default:              True
+
 flag luajit
   description:          Link with LuaJIT.  This implies flag system-lua as well.
   default:              False
@@ -171,6 +177,9 @@
 
   if flag(lua_32bits)
     cc-options:         "-DLUA_32BITS"
+
+  if flag(allow-unsafe-gc)
+    cc-options:         "-DALLOW_UNSAFE_GC"
 
   if flag(apicheck)
     cc-options:         "-DLUA_USE_APICHECK"
diff --git a/src/Foreign/Lua/Api.hs b/src/Foreign/Lua/Api.hs
--- a/src/Foreign/Lua/Api.hs
+++ b/src/Foreign/Lua/Api.hs
@@ -166,6 +166,9 @@
   , newmetatable
   , ref
   , unref
+  -- * Helper functions
+  , throwTopMessageAsError
+  , throwTopMessageAsError'
   ) where
 
 import Prelude hiding (EQ, LT, compare, concat)
@@ -198,9 +201,41 @@
   else return x
 
 throwTopMessageAsError :: Lua a
-throwTopMessageAsError = do
-  msg <- tostring (-1) <* pop 1
-  throwLuaError (BC.unpack msg)
+throwTopMessageAsError = throwTopMessageAsError' id
+
+throwTopMessageAsError' :: (String -> String) -> Lua a
+throwTopMessageAsError' msgMod = do
+  ty <- ltype (-1)
+  msg <- case ty of
+           TypeNil -> return "nil"
+           TypeBoolean -> show <$> toboolean (-1)
+           TypeLightUserdata -> showPointer
+           TypeNumber -> BC.unpack <$> tostring (-1)
+           TypeString -> BC.unpack <$> tostring (-1)
+           TypeTable  -> tryTostringMetaMethod
+           TypeFunction -> showPointer
+           TypeThread -> showPointer
+           TypeUserdata -> showPointer
+           TypeNone -> error "Error while receiving the error message!"
+  pop 1
+  throwLuaError (msgMod msg)
+ where
+  showPointer = show <$> topointer (-1)
+  tryTostringMetaMethod = do
+    hasMT <- getmetatable (-1)
+    if not hasMT
+      then showPointer
+      else do
+        -- push getmetatable(t).__tostring
+        pushstring (BC.pack "__tostring") *> rawget (-2)
+        remove (-2)              -- remove metatable from stack
+        isFn <- isfunction (-1)
+        if isFn
+          then do
+            insert (-2)
+            call 1 1
+            BC.unpack <$> tostring (-1)
+          else pop 1 *> showPointer
 
 --
 -- API functions
diff --git a/src/Foreign/Lua/Api/RawBindings.hsc b/src/Foreign/Lua/Api/RawBindings.hsc
--- a/src/Foreign/Lua/Api/RawBindings.hsc
+++ b/src/Foreign/Lua/Api/RawBindings.hsc
@@ -72,37 +72,69 @@
   lua_gettop :: LuaState -> IO StackIndex
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_settop lua_settop>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_settop"
+#else
+foreign import ccall safe "lua.h lua_settop"
+#endif
   lua_settop :: LuaState -> StackIndex -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushvalue lua_pushvalue>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushvalue"
+#else
+foreign import ccall safe "lua.h lua_pushvalue"
+#endif
   lua_pushvalue :: LuaState -> StackIndex -> IO ()
 
 #if LUA_VERSION_NUMBER >= 503
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rotate lua_rotate>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rotate"
+#else
+foreign import ccall "lua.h lua_rotate"
+#endif
   lua_rotate :: LuaState -> StackIndex -> CInt -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_copy lua_copy>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_copy"
+#else
+foreign import ccall "lua.h lua_copy"
+#endif
   lua_copy :: LuaState -> StackIndex -> StackIndex -> IO ()
 #else
 -- | See <https://www.lua.org/manual/5.2/manual.html#lua_remove lua_remove>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_remove"
+#else
+foreign import ccall safe "lua.h lua_remove"
+#endif
   lua_remove :: LuaState -> StackIndex -> IO ()
 
 -- | See <https://www.lua.org/manual/5.2/manual.html#lua_insert lua_insert>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_insert"
+#else
+foreign import ccall safe "lua.h lua_insert"
+#endif
   lua_insert :: LuaState -> StackIndex -> IO ()
 
 -- | See <https://www.lua.org/manual/5.2/manual.html#lua_replace lua_replace>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_replace"
+#else
+foreign import ccall safe "lua.h lua_replace"
+#endif
   lua_replace :: LuaState -> StackIndex -> IO ()
 #endif
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_checkstack lua_checkstack>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_checkstack"
+#else
+foreign import ccall safe "lua.h lua_checkstack"
+#endif
   lua_checkstack :: LuaState -> StackIndex -> IO LuaBool
 
 -- lua_xmove is currently not supported.
@@ -112,27 +144,51 @@
 -- * Stack access functions
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_isnumber lua_isnumber>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_isnumber"
+#else
+foreign import ccall safe "lua.h lua_isnumber"
+#endif
   lua_isnumber :: LuaState -> StackIndex -> IO LuaBool
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_isstring lua_isstring>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_isstring"
+#else
+foreign import ccall safe "lua.h lua_isstring"
+#endif
   lua_isstring :: LuaState -> StackIndex -> IO LuaBool
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_iscfunction lua_iscfunction>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_iscfunction"
+#else
+foreign import ccall safe "lua.h lua_iscfunction"
+#endif
   lua_iscfunction :: LuaState -> StackIndex -> IO LuaBool
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_isuserdata lua_isuserdata>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_isuserdata"
+#else
+foreign import ccall safe "lua.h lua_isuserdata"
+#endif
   lua_isuserdata :: LuaState -> StackIndex -> IO LuaBool
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_type lua_type>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_type"
+#else
+foreign import ccall safe "lua.h lua_type"
+#endif
   lua_type :: LuaState -> StackIndex -> IO TypeCode
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_typename lua_typename>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_typename"
+#else
+foreign import ccall safe "lua.h lua_typename"
+#endif
   lua_typename :: LuaState -> TypeCode -> IO (Ptr CChar)
 
 -- lua_compare is unsafe (might cause a longjmp), use hslua_compare instead.
@@ -153,52 +209,96 @@
 #endif
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawequal lua_rawequal>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rawequal"
+#else
+foreign import ccall safe "lua.h lua_rawequal"
+#endif
   lua_rawequal :: LuaState -> StackIndex -> StackIndex -> IO LuaBool
 
 --
 -- Type coercion
 --
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_toboolean lua_toboolean>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_toboolean"
+#else
+foreign import ccall safe "lua.h lua_toboolean"
+#endif
   lua_toboolean :: LuaState -> StackIndex -> IO StackIndex
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tocfunction lua_tocfunction>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tocfunction"
+#else
+foreign import ccall safe "lua.h lua_tocfunction"
+#endif
   lua_tocfunction :: LuaState -> StackIndex -> IO CFunction
 
 #if LUA_VERSION_NUMBER >= 502
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tointegerx lua_tointegerx>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tointegerx"
+#else
+foreign import ccall safe "lua.h lua_tointegerx"
+#endif
   lua_tointegerx :: LuaState -> StackIndex -> Ptr LuaBool -> IO LuaInteger
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tonumberx lua_tonumberx>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tonumberx"
+#else
+foreign import ccall safe "lua.h lua_tonumberx"
+#endif
   lua_tonumberx :: LuaState -> StackIndex -> Ptr LuaBool -> IO LuaNumber
 #else
 -- | See <https://www.lua.org/manual/5.1/manual.html#lua_tointeger lua_tointeger>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tointeger"
+#else
+foreign import ccall safe "lua.h lua_tointeger"
+#endif
   lua_tointeger :: LuaState -> StackIndex -> IO LuaInteger
 
 -- | See <https://www.lua.org/manual/5.1/manual.html#lua_tonumber lua_tonumber>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tonumber"
+#else
+foreign import ccall safe "lua.h lua_tonumber"
+#endif
   lua_tonumber :: LuaState -> StackIndex -> IO LuaNumber
 #endif
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tolstring lua_tolstring>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tolstring"
+#else
+foreign import ccall safe "lua.h lua_tolstring"
+#endif
   lua_tolstring :: LuaState -> StackIndex -> Ptr CSize -> IO (Ptr CChar)
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_topointer lua_topointer>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_topointer"
+#else
+foreign import ccall safe "lua.h lua_topointer"
+#endif
   lua_topointer :: LuaState -> StackIndex -> IO (Ptr ())
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_tothread lua_tothread>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_tothread"
+#else
+foreign import ccall safe "lua.h lua_tothread"
+#endif
   lua_tothread :: LuaState -> StackIndex -> IO LuaState
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_touserdata lua_touserdata>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_touserdata"
+#else
+foreign import ccall safe "lua.h lua_touserdata"
+#endif
   lua_touserdata :: LuaState -> StackIndex -> IO (Ptr a)
 
 
@@ -208,11 +308,19 @@
 
 #if LUA_VERSION_NUMBER >= 502
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawlen lua_rawlen>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rawlen"
+#else
+foreign import ccall safe "lua.h lua_rawlen"
+#endif
   lua_rawlen :: LuaState -> StackIndex -> IO CSize
 #else
 -- | See <https://www.lua.org/manual/5.1/manual.html#lua_objlen lua_objlen>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_objlen"
+#else
+foreign import ccall safe "lua.h lua_objlen"
+#endif
   lua_objlen :: LuaState -> StackIndex -> IO CSize
 #endif
 
@@ -221,38 +329,70 @@
 -- * Push functions
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushnil lua_pushnil>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushnil"
+#else
+foreign import ccall safe "lua.h lua_pushnil"
+#endif
   lua_pushnil :: LuaState -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushnumber lua_pushnumber>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushnumber"
+#else
+foreign import ccall safe "lua.h lua_pushnumber"
+#endif
   lua_pushnumber :: LuaState -> LuaNumber -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushinteger lua_pushinteger>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushinteger"
+#else
+foreign import ccall safe "lua.h lua_pushinteger"
+#endif
   lua_pushinteger :: LuaState -> LuaInteger -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushlstring lua_pushlstring>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushlstring"
+#else
+foreign import ccall safe "lua.h lua_pushlstring"
+#endif
   lua_pushlstring :: LuaState -> Ptr CChar -> CSize -> IO ()
 
 -- lua_pushstring is currently not supported. It's difficult to use in a haskell
 -- context.
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushcclosure lua_pushcclosure>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushcclosure"
+#else
+foreign import ccall safe "lua.h lua_pushcclosure"
+#endif
   lua_pushcclosure :: LuaState -> CFunction -> NumArgs -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushboolean lua_pushboolean>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushboolean"
+#else
+foreign import ccall safe "lua.h lua_pushboolean"
+#endif
   lua_pushboolean :: LuaState -> LuaBool -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushlightuserdata lua_pushlightuserdata>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushlightuserdata"
+#else
+foreign import ccall safe "lua.h lua_pushlightuserdata"
+#endif
   lua_pushlightuserdata :: LuaState -> Ptr a -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_pushthread lua_pushthread>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_pushthread"
+#else
+foreign import ccall safe "lua.h lua_pushthread"
+#endif
   lua_pushthread :: LuaState -> IO CInt
 
 
@@ -275,23 +415,43 @@
   hslua_getfield :: LuaState -> StackIndex -> Ptr CChar -> IO CInt
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawget lua_rawget>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rawget"
+#else
+foreign import ccall safe "lua.h lua_rawget"
+#endif
   lua_rawget :: LuaState -> StackIndex -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawgeti lua_rawgeti>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rawgeti"
+#else
+foreign import ccall safe "lua.h lua_rawgeti"
+#endif
   lua_rawgeti :: LuaState -> StackIndex -> CInt -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_createtable lua_createtable>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_createtable"
+#else
+foreign import ccall safe "lua.h lua_createtable"
+#endif
   lua_createtable :: LuaState -> CInt -> CInt -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_newuserdata lua_newuserdata>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_newuserdata"
+#else
+foreign import ccall safe "lua.h lua_newuserdata"
+#endif
   lua_newuserdata :: LuaState -> CInt -> IO (Ptr ())
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_getmetatable lua_getmetatable>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_getmetatable"
+#else
+foreign import ccall safe "lua.h lua_getmetatable"
+#endif
   lua_getmetatable :: LuaState -> StackIndex -> IO CInt
 
 -- | Wrapper around <https://lua.org/manual/5.3/manual.html#lua_getglobal \
@@ -319,15 +479,27 @@
   hslua_setfield :: LuaState -> StackIndex -> Ptr CChar -> IO CInt
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawset lua_rawset>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rawset"
+#else
+foreign import ccall safe "lua.h lua_rawset"
+#endif
   lua_rawset :: LuaState -> StackIndex -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_rawseti lua_rawseti>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_rawseti"
+#else
+foreign import ccall safe "lua.h lua_rawseti"
+#endif
   lua_rawseti :: LuaState -> StackIndex -> CInt -> IO ()
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#lua_setmetatable lua_setmetatable>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lua.h lua_setmetatable"
+#else
+foreign import ccall safe "lua.h lua_setmetatable"
+#endif
   lua_setmetatable :: LuaState -> StackIndex -> IO ()
 
 -- | Wrapper around <https://lua.org/manual/5.3/manual.html#lua_setglobal \
@@ -462,5 +634,9 @@
 #endif
 
 -- | See <https://www.lua.org/manual/5.3/manual.html#luaL_loadstring luaL_loadstring>
+#ifdef ALLOW_UNSAFE_GC
 foreign import ccall unsafe "lauxlib.h luaL_loadstring"
+#else
+foreign import ccall safe "lauxlib.h luaL_loadstring"
+#endif
   luaL_loadstring :: LuaState -> Ptr CChar -> IO StatusCode
diff --git a/src/Foreign/Lua/FunctionCalling.hs b/src/Foreign/Lua/FunctionCalling.hs
--- a/src/Foreign/Lua/FunctionCalling.hs
+++ b/src/Foreign/Lua/FunctionCalling.hs
@@ -56,7 +56,6 @@
   ) where
 
 import Control.Monad (when)
-import Data.ByteString.Char8 (unpack)
 import Foreign.C (CInt (..))
 import Foreign.Lua.Api
 import Foreign.Lua.Types
@@ -133,9 +132,9 @@
     getglobal' fnName
     x
     z <- pcall nargs 1 Nothing
-    if z /= OK
-      then tostring (-1) >>= throwLuaError . unpack
-      else peek (-1) <* pop 1
+    if z == OK
+      then peek (-1) <* pop 1
+      else throwTopMessageAsError
 
 instance (ToLuaStack a, LuaCallFunc b) => LuaCallFunc (a -> b) where
   callFunc' fnName pushArgs nargs x =
diff --git a/src/Foreign/Lua/Types/FromLuaStack.hs b/src/Foreign/Lua/Types/FromLuaStack.hs
--- a/src/Foreign/Lua/Types/FromLuaStack.hs
+++ b/src/Foreign/Lua/Types/FromLuaStack.hs
@@ -57,6 +57,7 @@
 
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
+import qualified Data.ByteString.Lazy as BL
 
 -- | Result returned when trying to get a value from the lua stack.
 type Result a = Either String a
@@ -115,6 +116,9 @@
 
 instance FromLuaStack T.Text where
   peek = fmap T.decodeUtf8 . peek
+
+instance FromLuaStack BL.ByteString where
+  peek = fmap BL.fromStrict . peek
 
 #if MIN_VERSION_base(4,8,0)
 instance {-# OVERLAPS #-} FromLuaStack [Char] where
diff --git a/src/Foreign/Lua/Types/ToLuaStack.hs b/src/Foreign/Lua/Types/ToLuaStack.hs
--- a/src/Foreign/Lua/Types/ToLuaStack.hs
+++ b/src/Foreign/Lua/Types/ToLuaStack.hs
@@ -53,6 +53,7 @@
 
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
+import qualified Data.ByteString.Lazy as BL
 
 -- | A value that can be pushed to the Lua stack.
 class ToLuaStack a where
@@ -83,6 +84,9 @@
 
 instance ToLuaStack T.Text where
   push = push . T.encodeUtf8
+
+instance ToLuaStack BL.ByteString where
+  push = push . BL.toStrict
 
 #if MIN_VERSION_base(4,8,0)
 instance {-# OVERLAPS #-} ToLuaStack [Char] where
diff --git a/test/Foreign/Lua/ApiTest.hs b/test/Foreign/Lua/ApiTest.hs
--- a/test/Foreign/Lua/ApiTest.hs
+++ b/test/Foreign/Lua/ApiTest.hs
@@ -37,6 +37,7 @@
 import Prelude hiding (compare)
 
 import Control.Monad (forM_)
+import Data.Monoid ((<>))
 import Foreign.Lua as Lua
 import Test.HsLua.Arbitrary ()
 import Test.HsLua.Util (luaTestCase, pushLuaExpr)
@@ -64,7 +65,7 @@
         rawequal (-1) (-3)
     ]
 
-  , testGroup "insert" $
+  , testGroup "insert"
     [ luaTestCase "inserts stack elements using negative indices" $ do
         pushLuaExpr "1, 2, 3, 4, 5, 6, 7, 8, 9"
         insert (-6)
@@ -226,7 +227,7 @@
           pushLuaExpr "function () error 'error in error handler' end"
           loadstring "error 'this fails'" *> pcall 0 0 (Just (-2))
 
-  , testCase "garbage collection" . runLua $ do
+  , testCase "garbage collection" . runLua $
       -- test that gc can be called with all constructors of type GCCONTROL.
       forM_ [GCSTOP .. GCSETSTEPMUL] $ \what -> (gc what 23)
 
@@ -247,6 +248,24 @@
       let n1 = fromType lt1
           n2 = fromType lt2
       in Prelude.compare n1 n2 == Prelude.compare lt1 lt2
+
+  , testCase "functions can throw a table as error message" $ do
+      let mt = "{__tostring = function (e) return e.error_code end}"
+      let err = "error(setmetatable({error_code = 23}," <> mt <> "))"
+      res <- runLua . tryLua $ openbase *> loadstring err *> call 0 0
+      assertEqual "wrong error message" (Left (LuaException "23")) res
+
+  , testCase "handling table errors won't leak" $ do
+      let mt = "{__tostring = function (e) return e.code end}"
+      let err = "error(setmetatable({code = 5}," <> mt <> "))"
+      let luaOp = do
+            openbase
+            oldtop <- gettop
+            _ <- tryLua $ loadstring err *> call 0 0
+            newtop <- gettop
+            return (newtop - oldtop)
+      res <- runLua luaOp
+      assertEqual "error handling leaks values to the stack" 0 res
   ]
 
 compareWith :: (LuaInteger -> LuaInteger -> Bool)
