It sounds like an enum would be perfect for your use case: you can pass a meaningful object to your Exception class, and the enum value itself can offer a either a meaningful error code or a meaningful string, depending on the situation where you catch the exception.
thrownewCustomException(INVALID_STATE);
It also has the added bonus of constraining your potential values. If however, there are too many different situations, which can overlap in error codes but could benefit from having specific error messages, the custom exception could be expanded to include a(n optional) message.
It sounds like an enum would be perfect for your use case: you can pass a meaningful object to your Exception class, and the enum value itself can offer a either a meaningful error code or a meaningful string, depending on the situation where you catch the exception.
It also has the added bonus of constraining your potential values. If however, there are too many different situations, which can overlap in error codes but could benefit from having specific error messages, the custom exception could be expanded to include a(n optional) message.