这个问题找到解决方案了: 之所以发生syscall frame 的错误,本质上还是因为 lua 在遇到错误的时候会进行 longjmp,即跳回安全点,这个过程对 goroutine 的栈造成了破坏。所以需要想办法避免 longjmp。在深入研究 lua 的源码后我发现 lua_error 会检查是否设置了安全位点setjmp来决定是否进行 longjmp 。如果没有设置,则检查用户是否设置了错误处理器,最后 fallback 到 panic 上。那么安全位点是什么时候设置的呢?其实很简单,就是调用 lua_pcall 的时候。这也是为什么该方法可以安全调用任何函数的原因。所以我们只要跳过该方法的调用,改为使用 call,同时设置错误处理器,就可以将不安全的错误用 go 接管。那么用 go 接管后,我们又该怎么返回错误呢?答案是进行简单的 panic 操作。然后在 call 的调用协程上 recover 就可以捕获这个错误。进一步讲,可以自己实现一个 lua_pcall,其底层实现是通过一个 lua_call 组合 panic 和 recover 来达成由 go 端接管 lua 错误处理的效果