actualbudget/actual · error · GenericFileError
File not found
Error message
File not found
What it means
GenericFileError thrown at the end of FilesService.update(): after the UPDATE ran (possibly affecting rows loosely), the code re-fetches the row with getRaw(id) and throws if it is null. This guards the return path — the file must exist and be readable after an update.
Source
Thrown at packages/sync-server/src/app-sync/services/files-service.ts:263
updates.push('deleted = ?');
params.push(boolToInt(fileUpdate.deleted));
}
if (updates.length > 0) {
query += ' ' + updates.join(', ') + ' WHERE id = ?';
params.push(id);
const res = this.accountDb.mutate(query, params);
if (res.changes !== 1) {
throw new GenericFileError('Could not update File', { id });
}
}
// Return the modified object
const rawFile = this.getRaw(id);
if (!rawFile) {
throw new GenericFileError('File not found', { id });
}
return this.validate(rawFile);
}
getRaw(fileId: FileId): RawFile | null {
return this.accountDb.first(`SELECT * FROM files WHERE id = ?`, [fileId]);
}
validate(rawFile: RawFile) {
const fileId = rawFile.id;
if (!isValidFileId(fileId)) {
throw new GenericFileError('Invalid file ID', { fileId });
}
let groupId: GroupId | null = null;
if (rawFile.group_id !== null) {
if (!isValidGroupId(rawFile.group_id)) {
throw new GenericFileError('Invalid group ID', {View on GitHub (pinned to d4334cb6e6)
Solutions
- Verify the file ID exists before calling update().
- Handle the concurrent-delete case: re-list files and stop updating deleted ones.
- Serialize file mutations (single writer / transactions) to avoid read-after-write races.
- Catch GenericFileError in the route and respond 404 instead of 500.
Example fix
// before const f = filesService.update(id, patch); // throws 'File not found' // after const f = filesService.getRaw(id) && filesService.update(id, patch);
Defensive patterns
Strategy: try-catch
Validate before calling
const raw = filesService.getRaw(id);
if (!raw) throw new Error(`File ${id} does not exist; skipping update`); Type guard
function isFileMissingAfterUpdate(err: unknown): err is Error {
return err instanceof Error && err.message === 'File not found';
} Try / catch
try {
return filesService.update(id, patch);
} catch (err) {
if (isFileMissingAfterUpdate(err)) {
// row vanished mid-update: re-list files and surface 404 to the client
return null;
}
throw err;
} Prevention
- Never call update with IDs not obtained from a fresh get/list.
- Avoid deleting files while sync requests are in flight.
- Use transactions so read-modify-write sequences are atomic.
- Map this error to a 404 response in route handlers.
When it happens
Trigger: The row was deleted after the UPDATE statement executed; getRaw returns null because the id never existed and the update's WHERE clause silently matched nothing before this check; database read inconsistency mid-transaction.
Common situations: Concurrent DELETE racing an in-flight update; calling update with a bogus id against a build where changes is not checked; hard-resetting the account DB while requests are open.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- File not found
- File does not exist or you don't have access to it
- Could not update File
- Invalid file ID
- Invalid group ID
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/638828119a574912.
Report an issue: GitHub.