JS Silent Errors
In this page:
What Makes an Error "Silent"
A silent error produces no crash, no visible error message, and no obvious sign anything went wrong -- the code simply does not do what was intended, which can be far more confusing to debug than a loud crash with a clear stack trace pointing at the problem.
Example: What Makes an Error "Silent"
function divide(a, b) {
if (b === 0) return; // no crash, no error - just wrong silently
return a / b;
}
console.log(divide(10, 0)); // undefined, no indication of why
Unhandled Promise Rejections
A Promise that rejects with no .catch() (or an async function whose error is never caught) produces an "unhandled rejection" -- the browser typically logs a warning to the console, but nothing in the running application actually reacts to or surfaces the failure to the user.
Example: Unhandled Promise Rejections
Promise.reject("Something failed"); // no .catch() - unhandled rejection warning only, nothing reacts
Empty or Overly Broad Catch Blocks
A catch block that does nothing with the caught error -- catch (e) {} -- suppresses the failure entirely, effectively hiding it from view.
This is sometimes done deliberately for a genuinely optional operation, but far more often it accidentally masks a real problem worth investigating.
Example: Empty or Overly Broad Catch Blocks
try {
JSON.parse("bad json");
} catch (e) {} // swallowed silently, hides a real problem
console.log("Continues as if nothing happened");
Silent Failures from Optional Chaining and ??
Optional chaining (?.) and nullish coalescing (??) are excellent for genuinely optional data, but overusing them everywhere can mask a case where a value being missing actually indicates a real bug -- silently falling back to undefined or a default instead of surfacing the unexpected condition.
Example: Silent Failures from Optional Chaining and ??
const user = { profile: null };
console.log(user.profile?.name ?? "Unknown"); // masks whether this is expected or a real bug
Detecting Silent Failures
Tools exist specifically to surface silent failures: the browser's unhandledrejection event fires for any Promise rejection with no .catch(), and linters can flag empty catch blocks or missing return statements automatically, catching many silent-failure patterns before they ever reach production.
Example: Detecting Silent Failures
window.addEventListener("unhandledrejection", (e) => console.log("Caught silent rejection:", e.reason));
Promise.reject("oops");
- Writing an async function or Promise chain with no .catch() (or try/catch around await), letting a rejection disappear silently instead of surfacing as a visible error.
- Using optional chaining (?.) so liberally that a genuinely unexpected missing property silently returns undefined instead of surfacing as a helpful error close to its actual source.
- Catching an error broadly and doing nothing with it (an empty catch block), effectively swallowing information that would have helped diagnose a real problem.
- A silent error is one that fails without any visible crash, warning, or console output -- often harder to notice and debug than a loud error.
- An unhandled Promise rejection (no .catch()) is a very common source of silent failures in asynchronous code.
- An empty or overly broad catch block can accidentally suppress genuinely useful error information.
The browser's unhandledrejection event and console warnings for silent failures are supported in every modern browser, helping surface issues that would otherwise go unnoticed.
Chapter Quiz — Complete all 6 topics to unlock
0/6 topics done
Complete these topics first: