Why this matters

The bug. return promise finishes the function synchronously, returning the promise object itself. The promise may *later* reject, but at that point it's the caller's promise — your catch (err) is no longer in scope. Network errors bubble up to whatever awaits safeFetch, defeating the function's entire purpose.

The fix. return await promise keeps the awaiting inside this function's try, so a rejection unwinds into the catch. The 'return-await' pattern used to be flagged as redundant by older lints (no-return-await); the modern lint rule @typescript-eslint/return-await recognizes the try/catch case and requires it.

Subtle. Top-level return promise outside a try is genuinely equivalent to return await promise performance-wise (both await the same underlying work). It's *only* the in-try case where the await is semantically required.

Review heuristic

Read every async function twice: once for missing awaits, once for unnecessary awaits. The first set causes incorrectness; the second set causes performance regressions that nobody notices until the API gets slow.