verified that dofile() produces the same problem.
Right, every way of running lua code will go through something like pcall.
Anything that does C->lua->C->lua->C->yield(), because this would require somehow yielding the middle C call.
To put this in CHDK context,
kbd.c does the first C->lua, to run your lua script for a while in the KBD task. If you call pcall, dofile etc this introduces the next C call, and press() etc make up the final C->yield().
If you google or search the lua list archives for "attempt to yield across metamethod/C-call boundary" you should find more details.
If you look at lib/lua/ldo.c you can see where this happens. You'll also see luaD_rawrunprotected, which is where the setjmp at the heart of lua error handling happens.