Does this also happen with a fresh authorization code exchanged immediately, on its first attempt? Could you check that code_verifier is the original unhashed value used to generate the S256 challenge, and that redirect_uri exactly matches the authorization request? Please don't post the code, verifier, or any tokens here.