actualbudget/actual · info · PostError

aborted

aborted

Error message

aborted

What it means

PostError with sentinel message 'aborted' thrown by post when the caller-supplied AbortSignal fired and fetch rejected with an AbortError — i.e. the request was cancelled by the caller, not a timeout or network fault.

Source

Thrown at packages/loot-core/src/server/post.ts:86

  try {
    const signal = timeout != null || externalSignal ? controller.signal : null;
    res = await fetch(url, {
      method: 'POST',
      body: JSON.stringify(data),
      signal,
      headers: {
        ...headers,
        'Content-Type': 'application/json',
      },
    });
    text = await res.text();
  } catch (err) {
    if (
      err instanceof Error &&
      err.name === 'AbortError' &&
      externalSignal?.aborted
    ) {
      throw new PostError('aborted');
    }
    throw new PostError('network-failure', undefined, { cause: err });
  } finally {
    if (timeoutId != null) clearTimeout(timeoutId);
    externalSignal?.removeEventListener('abort', onExternalAbort);
  }

  throwIfNot200(res, text);

  let responseData;

  try {
    responseData = JSON.parse(text);
  } catch {
    // Something seriously went wrong. TODO handle errors
    throw new PostError('parse-json', { meta: text });
  }

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Catch PostError 'aborted' and treat it as an expected cancellation, not a failure
  2. Only abort the signal when cancellation is truly intended
  3. If aborts are accidental, stop aborting controllers on unmount/hide
  4. Re-issue the request if the operation must complete

Example fix

// before
try { await post(url, data, { signal: controller.signal }); } catch (e) { throw e; }
// after
try { await post(url, data, { signal: controller.signal }); }
catch (e) {
  if (e instanceof PostError && e.message === 'aborted') return; // cancelled by us
  throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// only wire an AbortController if cancellation is genuinely needed
const controller = shouldAllowCancel ? new AbortController() : null;

Type guard

function isAbortError(e: unknown): e is PostError {
  return e instanceof PostError && e.message === 'aborted';
}

Try / catch

try {
  await post(url, data, { signal: controller?.signal });
} catch (e) {
  if (isAbortError(e)) return; // expected cancellation — ignore
  throw e;
}

Prevention

When it happens

Trigger: Passing an externalSignal to post() and aborting it (via AbortController.abort()) while the request is in flight; component unmount cancelling a sync request.

Common situations: UI cancelling a slow sync when navigating away, user pressing a cancel button, React effects aborting fetches on cleanup, duplicate-request suppression aborting the older call.

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/7530704ecec5fec8. Report an issue: GitHub.