With $wgReadOnly set and when $wgSessionCacheType = CACHE_DB, ApiQueryTokens will return invalid tokens. The token will result in a code: "badtoken" error when used, and action=checktoken confirms they are invalid.
I suspect that this is because it can't persist the session in the database (ApiQueryTokens::getToken calls $session->persist()). There is no error checking for this at all, anywhere, as far as I can see.
ApiQueryTokens should probably return a code: "readonly" error in this case. It's not like the tokens are useful for much anyway if the site is readonly.
This doesn't always happen; I suppose it works if a session is already persisted? I've had trouble with this error disappearing when I tried to reproduce it, and reappearing when I gave up.