Some notes of APIs that I’ve seen and disliked, followed by suggestions on how to make them, in my opinion, at least a bit better. Basically, this is a a collection of recurrent conversations that I’ve seen on code review.

Additional out parameter for signaling error

// Given
bool fileContents(const String& name, String& contents); // returns bool on success to read

// Usage (ignoring error)
String contents;
fileContents("/etc/passwd", contents); // Modifiable reference invisible without IDE support
// Use the contents, but now are not const even if we don't change the file!

// Usage (handling error)
String contents;
if (fileContents("/etc/passwd", contents)) {
    // Use the contents
}
// contents variable still in scope, but invalid

Alternative:

// Asking for the error can be optional, given the default argument.
// The return value cannot be forgotten accidentally (which would make the code
// a pointless function call).
[[nodiscard]] String fileContents(const String& name, bool* ok = nullptr);

// Usage (ignoring error)
const String contents = fileContents("/etc/passwd"); // Now result can be const

// Usage (handling error)
bool ok = false;
if (const String contents = fileContents("/etc/passwd", &ok); ok) {
    // Use the contents
}
// contents variable not in scope, but the error check one is