Finally figured it out. It seems to be both Teradata and Crystal and how they're communicating.
The report ran fine for 2 years, and then after a Teradata driver update, began producing the error.
After much research and testing, finally figured out that Crystal was sending a loan number parameter as numeric now when it used to send it as a string (should be a string since it as leading zeros). I solved the issue by putting single quotes around the parameter object in the SQL command.
Curiously, all other sub-reports in this report also use the loan number parameter, and it is sent correctly as a string in all of those. It's only in the custom SQL where it suddenly started sending it as numeric.