Promise, but don’t punish: In each function, give the strongest safety guarantee that won’t penalize callers who don’t need it. Always give at least the basic guarantee.
Ensure that errors always leave your program in a valid state. This is the basic guarantee. Beware of invariant-destroying errors (including but not limited to leaks), which are just plain bugs.
Prefer to additionally guarantee that the final state is either the original state (if there was an error the operation was rolled back) or the intended target state (if there was no error the operation was committed). This is the strong guarantee.
Prefer to additionally guarantee that the operation can never fail at all. Although this is ...