actualbudget/actual · error · PostError

unknown

unknown

Error message

res.description || res.reason || 'unknown'

What it means

`del` throws this PostError when the server responds 200 with JSON whose status is not 'ok'; the message is the server's `description` or `reason`, else 'unknown'. It is a server-reported application failure for the delete operation, with request data and response logged.

Source

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

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

  if (res.status !== 'ok') {
    logger.log(
      'API call failed: ' +
        url +
        '\nData: ' +
        JSON.stringify(data, null, 2) +
        '\nResponse: ' +
        JSON.stringify(res, null, 2),
    );

    throw new PostError(res.description || res.reason || 'unknown');
  }

  return res.data;
}

export async function patch(url, data, headers = {}, timeout = null) {
  let text;
  let res;

  try {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), timeout);
    const signal = timeout ? controller.signal : null;
    res = await fetch(url, {
      method: 'PATCH',
      body: JSON.stringify(data),
      signal,
      headers: {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Check the thrown message and the logged request/response for the server's reason.
  2. Re-authenticate if the reason indicates an unauthorized/token problem.
  3. Confirm the file still exists and belongs to the current user before deleting.
  4. Check sync server logs for the failing request when the message is 'unknown'.
  5. Align client and server versions.

Example fix

// before: deleting with a token from a different user account
await del(server + '/delete-user-file', { token: otherUserToken, fileId });
// after: ensure the file belongs to the signed-in user
const files = await getServerFiles(token); // verify ownership first
if (files.some(f => f.fileId === fileId)) await del(server + '/delete-user-file', { token, fileId });
Defensive patterns

Strategy: try-catch

Validate before calling

// check ownership before deleting
const files = await getServerFiles(token);
if (!files.some(f => f.fileId === fileId)) throw new Error(`File ${fileId} not found for current user`);

Type guard

function isServerRejection(e: unknown): e is { reason: string } {
  return typeof e === 'object' && e !== null && typeof (e as any).reason === 'string' && (e as any).reason !== 'ok';
}

Try / catch

try {
  await del(server + '/delete-user-file', { token, fileId });
} catch (e) {
  if (isServerRejection(e) && /token|unauthorized/i.test(e.message)) {
    await reauthenticate();
  } else if (isServerRejection(e) && /not-found/i.test(e.message)) {
    // file already gone: treat as idempotent success
  } else throw e;
}

Prevention

When it happens

Trigger: del() call rejected by the server: invalid/expired user token, file ID not owned by the user, or other server-side validation on the delete endpoint responding {status: ..., description/reason}.

Common situations: Token expired after server maintenance; attempting to delete a file already removed server-side; permission mismatch between the signed-in user and the file's owner; 'unknown' from a server version that omits reason fields.

Related errors


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