Skip to content

[Feature] wrapError helper for consistent try/catch error mapping #254

@pathosDev

Description

@pathosDev

Size / Priority

  • Size: Trivial (~50 call-sites consolidated)
  • Category: C.2 Simplifications & DRY.
  • Risk: low.

Affected files

  • Across src/cache/*, src/io/broker/*, src/persistence/* — every try { … } catch (e) { throw new XxxError(...) } pattern.

Background

The same shape repeats many times:

try {
  await client.doSomething();
} catch (e) {
  if (e instanceof XxxError) throw e;
  throw new XxxError(`XxxBackend.doSomething failed for key '${key}'`, e);
}

Two annoyances:

  1. The if-check instanceof XxxError — prevents double-wrapping when an inner call already wrapped. Easy to forget.
  2. Bespoke message format'XxxBackend.method failed for key X' repeated with manual variation.

Target code

// src/util/WrapError.ts (new)

/**
 * Re-throw if already typed; otherwise wrap with a context message.
 *
 *   try { ... } catch (e) { throw wrapError(e, MyError, 'context: foo failed for key', { key }); }
 */
export function wrapError<E extends Error>(
  e: unknown,
  ErrorClass: new (msg: string, cause?: unknown) => E,
  message: string,
  context?: Record<string, unknown>,
): E {
  if (e instanceof ErrorClass) return e;
  const ctxStr = context ? ` (${Object.entries(context).map(([k, v]) => `${k}=${String(v)}`).join(', ')})` : '';
  return new ErrorClass(`${message}${ctxStr}`, e);
}

Per-site usage:

try {
  await client.doSomething();
} catch (e) {
  throw wrapError(e, CacheError, `${this.name}.doSomething failed`, { key });
}

Integration / risk

Test plan

  1. Regression — error-throwing tests still report correct error class + message.
  2. Double-wrap prevention — nested wrap calls don't re-wrap.
  3. Context formatting — verify { key: 'foo' } becomes (key=foo).

Acceptance criteria

  • wrapError(e, Cls, msg, ctx?) exported.
  • All major call sites migrated.
  • Error messages still informative + consistent.
  • No CHANGELOG entry needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpriority: lowNice-to-have / niche / demand-driven

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions