@duckduckgo/content-scope-scripts
    Preparing search index...

    Intentional Error Management

    Thrown errors and unhandled promise rejections must be intentional and represent exceptional conditions, not part of the normal "happy path" of code execution.

    Do NOT use errors as a mechanism for normal control flow:

    // BAD: Using errors for expected conditions
    function getValue(key) {
    const value = map.get(key);
    if (!value) throw new Error('Key not found'); // Expected case!
    return value;
    }

    // GOOD: Return a sentinel or optional value
    function getValue(key) {
    return map.get(key) ?? null;
    }

    Errors should be thrown only for:

    • Unreachable code paths (exhaustiveness checks):

      switch (type) {
      case 'a': return handleA();
      case 'b': return handleB();
      default: throw new Error('unreachable');
      }
    • Invalid invariants (programmer errors, not user errors):

      if (!this.args) throw new Error('messaging requires args to be set');
      if (!(manager instanceof VideoOverlay)) throw new Error('invalid arguments');
    • Missing required dependencies:

      if (!_messagingModuleScope) throw new Error('Messaging not initialized');
      
    • Never leave promises unhandled - always attach .catch() or use try/catch with await

    • Use Promise.reject() only when mimicking browser API behavior (e.g., web-compat.js returning DOMException):

      // Mimicking native Share API behavior
      if (!canShare(data)) return Promise.reject(new TypeError('Invalid share data'));
    • Handle async errors explicitly:

      // GOOD: Explicit error handling
      await this.setUserChoice(choice).catch((e) => console.error('error setting user choice', e));

      // GOOD: Swallow expected failures intentionally
      await fetchOptional().catch(() => {}); // Comment explaining why this is OK

    Use assertion functions for type/state validation that throws on failure:

    /**
    * @returns {asserts event is CustomEvent<{kind: string, data: any}>}
    */
    function assertCustomEvent(event) {
    if (!('detail' in event)) throw new Error('none-custom event');
    if (typeof event.detail.kind !== 'string') throw new Error('custom event requires detail.kind to be a string');
    }
    • Error messages should clearly indicate what went wrong and why it's a bug
    • Include context that helps debugging:
      throw new Error(`'${method.toString()}' is not a method of feature '${this.name}'`);
      
    Anti-Pattern Problem Solution
    Empty catch blocks Silently swallows errors Log or re-throw with context
    Throwing for expected null/undefined Using errors as control flow Return optional/sentinel values
    Unhandled promise chains Leads to unhandled rejections Add .catch() handler
    Generic error messages Hard to debug Include specific context
    Catching and ignoring all errors Masks bugs Catch specific error types

    The codebase enforces:

    • require-await - async functions must use await
    • promise/prefer-await-to-then - prefer async/await over .then()
    • @typescript-eslint/await-thenable - only await promises
    • Errors = exceptional conditions (bugs, invariant violations, unreachable code)
    • Errors ≠ expected conditions (missing data, user input validation, optional features)
    • Every promise rejection must be handled or intentionally propagated