From d9ad8db7140ad6be2100b36d703b4fdeecc06b43 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Wed, 20 May 2026 12:32:44 -0400 Subject: [PATCH] fix: Preserve OpenAI files on quota rejection --- api/server/services/Files/process.js | 2 +- api/server/services/Files/process.spec.js | 36 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/api/server/services/Files/process.js b/api/server/services/Files/process.js index 88049545ed..f11d3f4bd5 100644 --- a/api/server/services/Files/process.js +++ b/api/server/services/Files/process.js @@ -1219,7 +1219,7 @@ const processOpenAIFile = async ({ }; if (saveFile) { - await createFileWithStorageLimit(request, file, true, { openai }); + await createFileWithStorageLimit(request, file, true, { cleanup: false }); } else if (updateUsage) { try { await db.updateFileUsage({ file_id }); diff --git a/api/server/services/Files/process.spec.js b/api/server/services/Files/process.spec.js index 31fdb2678d..89db793b7c 100644 --- a/api/server/services/Files/process.spec.js +++ b/api/server/services/Files/process.spec.js @@ -1392,6 +1392,42 @@ describe('generated image quota paths', () => { ); }); + it('retrieveAndProcessFile does not delete existing OpenAI files when metadata quota rejects', async () => { + const error = Object.assign(new Error('storage limit exceeded.'), { + code: 'FILE_STORAGE_LIMIT_EXCEEDED', + status: 413, + }); + const req = { + user: { id: 'user-123', tenantId: 'tenant-a' }, + body: { endpoint: EModelEndpoint.assistants, model: 'gpt-4o' }, + config: { fileConfig: { storageLimit: 1 } }, + }; + const openai = { + baseURL: 'https://api.openai.test', + files: { + retrieve: jest.fn().mockResolvedValue({ + bytes: 512, + filename: 'remote.txt', + purpose: 'assistants_output', + }), + }, + }; + const deleteFile = jest.fn(); + getStrategyFunctions.mockReturnValue({ deleteFile }); + assertFileStorageLimit.mockRejectedValueOnce(error); + + await expect( + retrieveAndProcessFile({ + openai, + client: { req }, + file_id: 'openai-file-id', + }), + ).rejects.toThrow('storage limit exceeded'); + + expect(deleteFile).not.toHaveBeenCalled(); + expect(db.createFile).not.toHaveBeenCalled(); + }); + it('retrieveAndProcessFile rejects over-limit OpenAI image outputs before metadata persistence', async () => { const error = Object.assign(new Error('storage limit exceeded.'), { code: 'FILE_STORAGE_LIMIT_EXCEEDED',