diff --git a/test/box/misc.result b/test/box/misc.result
index 9488a70b35931f6ac1d4f0ea478dd63f2ec24e4b..911d71b10de00be32ce8d9b249f1cd5b5f64471c 100644
--- a/test/box/misc.result
+++ b/test/box/misc.result
@@ -477,3 +477,105 @@ space:delete{1}
 space:drop()
 ---
 ...
+----------------
+-- # yaml encode/decode on cdata
+----------------
+ffi = require('ffi')
+---
+...
+ffi.new('uint8_t', 128)
+---
+- 128
+...
+ffi.new('int8_t', -128)
+---
+- -128
+...
+ffi.new('uint16_t', 128)
+---
+- 128
+...
+ffi.new('int16_t', -128)
+---
+- -128
+...
+ffi.new('uint32_t', 128)
+---
+- 128
+...
+ffi.new('int32_t', -128)
+---
+- -128
+...
+ffi.new('uint64_t', 128)
+---
+- 128
+...
+ffi.new('int64_t', -128)
+---
+- -128
+...
+ffi.new('char', 128)
+---
+- -128
+...
+ffi.new('char', -128)
+---
+- -128
+...
+ffi.new('bool', true)
+---
+- true
+...
+ffi.new('bool', false)
+---
+- false
+...
+ffi.new('float', 1.23456)
+---
+- 1.2345600128174
+...
+ffi.new('float', 1e10)
+---
+- 10000000000
+...
+ffi.new('double', 1.23456)
+---
+- 1.23456
+...
+ffi.new('double', 1e10)
+---
+- 10000000000
+...
+ffi.cast('void *', 0)
+---
+- null
+...
+ffi.cast('void *', 0xabcdef)
+---
+- 'cdata<void *>: 0x00abcdef'
+...
+ffi.cdef([[struct test { int a; }; ]])
+---
+...
+ffi.cast('struct test *', 0)
+---
+- 'cdata<struct test *>: NULL'
+...
+--# setopt delimiter ';'
+type(ffi.metatype('struct test', {
+    __index = {
+        totable = function(test)
+            return { 'yaml totable test = ' .. test.a }
+        end
+    }
+}));
+---
+- cdata
+...
+--# setopt delimiter ''
+-- custom totable function will be called by yaml.encode
+ffi.new('struct test', { a = 15 })
+---
+- - yaml totable test = 15
+...
diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua
index dd96ea48662bdd8762bcb0857ece41bf743ebf6f..df3f2bfacabb91cfc08a50c782f0087618742ecf 100644
--- a/test/box/misc.test.lua
+++ b/test/box/misc.test.lua
@@ -147,3 +147,47 @@ fifo_top(space, 1)
 space:delete{1}
 
 space:drop()
+
+----------------
+-- # yaml encode/decode on cdata
+----------------
+
+ffi = require('ffi')
+
+ffi.new('uint8_t', 128)
+ffi.new('int8_t', -128)
+ffi.new('uint16_t', 128)
+ffi.new('int16_t', -128)
+ffi.new('uint32_t', 128)
+ffi.new('int32_t', -128)
+ffi.new('uint64_t', 128)
+ffi.new('int64_t', -128)
+
+ffi.new('char', 128)
+ffi.new('char', -128)
+ffi.new('bool', true)
+ffi.new('bool', false)
+
+ffi.new('float', 1.23456)
+ffi.new('float', 1e10)
+ffi.new('double', 1.23456)
+ffi.new('double', 1e10)
+
+ffi.cast('void *', 0)
+ffi.cast('void *', 0xabcdef)
+
+ffi.cdef([[struct test { int a; }; ]])
+ffi.cast('struct test *', 0)
+
+--# setopt delimiter ';'
+type(ffi.metatype('struct test', {
+    __index = {
+        totable = function(test)
+            return { 'yaml totable test = ' .. test.a }
+        end
+    }
+}));
+
+--# setopt delimiter ''
+-- custom totable function will be called by yaml.encode
+ffi.new('struct test', { a = 15 })
diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc
index c462b3a64499827a8cd54fbc898a405a128583bc..b94ab2a013f94306ae599cdeea6a953353d35344 100644
--- a/third_party/lua-yaml/lyaml.cc
+++ b/third_party/lua-yaml/lyaml.cc
@@ -560,20 +560,29 @@ dump_node(struct lua_yaml_dumper *dumper)
 	int type = lua_type(dumper->L, top);
 	if (field.type == MP_EXT &&
 	    (type == LUA_TUSERDATA || type == LUA_TCDATA)) {
-		/* has metatable, try to call 'totable' and use return value */
-		lua_getfield(dumper->L, top, "totable");
-		if (lua_isfunction(dumper->L, -1)) {
-			lua_pushvalue(dumper->L, top); /* copy object itself */
-			lua_call(dumper->L, 1, 1);
-			lua_replace(dumper->L, top);
-			luaL_tofield(dumper->L, -1, &field);
-		} else {
-			lua_pop(dumper->L, 1); /* pop result */
+		/* try to call 'totable' method on udata/cdata */
+		try {
+			/*
+			 * LuaJIT specific: lua_getfield raises exception on
+			 * cdata objects if field doesn't exist.
+			 */
+			lua_getfield(dumper->L, top, "totable");
+			if (lua_isfunction(dumper->L, -1)) {
+				/* copy object itself */
+				lua_pushvalue(dumper->L, top);
+				lua_call(dumper->L, 1, 1);
+				if (lua_istable(dumper->L, -1)) {
+					/* replace obj with the unpacked table*/
+					lua_replace(dumper->L, top);
+					luaL_tofield(dumper->L, -1, &field);
+				}
+			}
+		} catch (...) {
+			/* ignore lua_getfield exceptions */
 		}
+		lua_settop(dumper->L, top); /* remove temporary objects */
 	}
 
-	luaL_tofield(dumper->L, top, &field);
-
 	/* Still have unknown type on the stack,
 	 * try to call 'tostring' */
 	if (field.type == MP_EXT) {