Dynamic
doesn't work the way you think it does. See this answer for a full explanation.
In short, Dynamic
doesn't do anything until it is actually displayed on screen.
Therefore, you are essentially doing this (note the String):
MapThread[f, {"Dynamic[ls]", {10, 20, 30}}]
As acl already showed, you can wrap the entire expression in Dynamic
so that it does not attempt to evaluate the failing condition shown above.