To provide a bit of colour on this, the CVC is calculated as a function of the PAN (aka the card number), the expiration date, and the service code of the card, which are encrypted/MAC'd with secret keys belonging to the card issuer. [0] When the issuing bank processes an authorization request, it recomputes the CVC with this method, and compares it with the value supplied by the user. Interestingly, some issuing banks seem to use the *user-supplied* expiration date as an input to this computation - so, if the wrong expiration date is supplied, the CVC calculated by the bank will be wrong. When this incorrect value is compared against the (correct) user-supplied CVC, this causes the validation message that you described above.
While there's a totally coherent argument to be made that this is a bug, this is a bug in the the issuing bank's code. Moreover, Stripe has no way of distinguishing "real" CVC validation issues from expiration date validation failing, so there isn't really a viable downstream fix.
Hopefully this provides a bit more context about why this behaviour exists.
Cheers,
Peter