actualbudget/actual · error

invalid-file-id

invalid-file-id

Error message

File not found at server

What it means

The file deletion/validation path calls `UserService.getFileById(fileId)`; if no file row matches, it responds 404 with reason 'invalid-file-id' and details 'File not found at server'. The server only permits operations on files it actually tracks in its files table.

Source

Thrown at packages/sync-server/src/app-admin.js:208

  const { granted } = UserService.checkFilePermission(
    fileId,
    res.locals.user_id,
  ) || {
    granted: 0,
  };

  if (granted === 0 && !isAdmin(res.locals.user_id)) {
    res.status(403).send({
      status: 'error',
      reason: 'forbidden',
      details: 'permission-not-found',
    });
    return false;
  }

  const fileIdInDb = UserService.getFileById(fileId);
  if (!fileIdInDb) {
    res.status(404).send({
      status: 'error',
      reason: 'invalid-file-id',
      details: 'File not found at server',
    });
    return false;
  }

  const accesses = UserService.getUserAccess(
    fileId,
    res.locals.user_id,
    isAdmin(res.locals.user_id),
  );

  res.json(accesses);
});

app.post('/access', (req, res) => {
  const userAccess = req.body || {};

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Verify the fileId against the server's file list (user-get-files) and use only ids present there.
  2. Treat 404 as already-deleted and remove the file from local metadata instead of retrying.
  3. Confirm the client is connected to the same sync server that hosts the file (check GOAL_SERVER_URL / server URL config).
  4. If the file should exist, re-upload/sync it from the client to register it, then retry the operation.

Example fix

// before
await deleteFile({ fileId: localFileId }); // file never synced to this server
// after
const files = await getUserFiles();
if (files.some(f => f.fileId === localFileId)) {
  await deleteFile({ fileId: localFileId });
}
Defensive patterns

Strategy: validation

Validate before calling

const files = await getUserFiles(); // server-side listing
if (!files.some(f => f.fileId === fileId)) {
  throw new Error(`File ${fileId} not present on server; nothing to delete`);
}

Type guard

function isKnownFileId(fileId: string, serverFiles: { fileId: string }[]): boolean {
  return serverFiles.some(f => f.fileId === fileId);
}

Try / catch

try {
  await deleteFile({ fileId });
} catch (e) {
  if (e.status === 404 && e.reason === 'invalid-file-id') {
    // already deleted or never synced: clean up local metadata only
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: DELETE /user-delete-file (or similar file endpoint) with a fileId that does not exist on the server — already deleted, a local-only file never synced, an id from another server, or a mistyped uuid.

Common situations: Deleting a file on the server after it was already removed (double cleanup); pointing a client at a fresh sync-server instance while reusing ids from the old instance; local files created offline that were never uploaded; corrupted client metadata holding stale file ids.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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