Fail Safe Error Propagation

Establish an error-handling standard that prevents crashes/hangs, preserves root errors, and makes recovery bounded and verifiable. Guidelines: - Catch safely: prefer `catch (err: unknown)` and narrow before reading fields.

copy reviewer prompt

Prompt

Reviewer Prompt

Establish an error-handling standard that prevents crashes/hangs, preserves root errors, and makes recovery bounded and verifiable.

Guidelines:

  • Catch safely: prefer catch (err: unknown) and narrow before reading fields.
  • Propagate failures to consumers: for streams/transforms, call controller.error(err) (not enqueue/continue) and perform deterministic teardown/abort.
  • Fail safe on corrupted/unknown inputs: when runtime data may be corrupted, never throw from “read/execute” paths; fall back to a default and keep stricter validation only on writes.
  • Bounded fallback/retry: only retry transient connection/dispatcher errors; cap attempts; respect remaining timeout budget.
  • Retry guard for request bodies: if the body is non-replayable (stream/Blob), do not retry.
  • Don’t shadow the root error: cleanup/rollback failures must not replace the original exception.
  • Don’t silently misclassify: when a status code is ambiguous (e.g., 403), decide validity based on explicit evidence (message/body patterns) and cover with tests.

Example (SSE transform fail propagation + streaming semantics):

return new TransformStream({
  transform(chunk, controller) {
    try {
      // parse/process...
    } catch (err) {
      // Propagate and abort the SSE pipeline
      controller.error(err);
    }
  }
});

Example (guarded retry with non-replayable body check):

const bodyUnknown = options.body as unknown;
const isBodyStream =
  bodyUnknown && typeof bodyUnknown === 'object' &&
  (typeof (bodyUnknown as any).getReader === 'function');
const maxAttempts = isBodyStream ? 1 : 2;

for (let attempt = 0; attempt < maxAttempts; attempt++) {
  try {
    return await undiciDirect(input, { ...options, dispatcher });
  } catch (e) {
    const code = (e as { code?: string }).code;
    if (code === 'ECONNREFUSED' || String(e).includes('fetch failed')) continue;
    throw e;
  }
}

Source discussions