The problem you are running into is a very common one, and the reason why the software design rules around avoiding Magic Numbers and Magic Strings exist. The common solution to the problem is to move the offending value into a single location so it is easier to change. This is usually done through the use of a file for the data (constants file, config file, json file loaded at start, etc). Then, instead of referencing the value directly, your code can be updated to reference the loaded data.
Depending on how deep of a dive into Object Oriented Programming you want to do, you can drive a lot of your code through these kinds of files. A couple years ago I built out a utility for a game I was designing, and because I was still developing technologies, buildings, skills, etc for it, I wanted to make it as generic as possible. I created the basic shell for each object, and populated any important values from a file loaded at startup (for example, my code didn't know that a Barn existed, but it did know that it could have a list of buildings loaded from a file, which happened to contain a Barn object).
The more OOP you go in this way, the easier it is to change values and inputs, but the more complex the code needs to be in terms of error handling. In my example, let's say that a user's data I am loading has reference to the Research Station building, but my buildings file no longer has that building in it. I need to be able to handle that situation, however I decide is appropriate. In your scenario, what happens if you dynamically load an upgrade that has 50 levels, but when your player starts up, their save has 51 levels of upgrades for it?
I'll also add that the vast majority of idle games with upgrades use a multiplier instead of fixed pricing for their upgrades. instead of knowing the cost of each of the million upgrades, it knows that the upgrade cost is some formula like *1.07^(upgrade level) I'm not certain from your post if you are hard coding them all, or if you are using a multiplier.