[Bug]: error when downloading multiple budgets #2336

Closed
opened 2026-02-28 20:10:56 -06:00 by GiteaMirror · 2 comments
Owner

Originally created by @m-schwob on GitHub (Aug 1, 2025).

Verified issue does not already exist?

  • I have searched and found no existing issue

What happened?

Description:
When using the API to download multiple budgets sequentially via downloadBudget(), an error App: startServices called while services are already running is thrown starting from the second budget. The operation still completes successfully.

How can we reproduce the issue?

Environment:

  • Actual Budget API version and Actual Server docker image version: v25.6.1

I tried to run the minimal code using v25.7.1 it gave me "Database is out of sync with migrations" error, which I couldn't solve (might need to open another issue for it).

  • Authentication: password
  • Fresh server with two budget files
  • Clean dataDir folder (the minimal example does not handle the local budget case)

Minimal Code

import * as api from '@actual-app/api';

// NOTE: This test assumes:
// - a server is running with 2 budgets available.
// - local folder './data/budgets' is empty without previously downloaded budgets

async function test() {
    await api.init({
        dataDir: './data/budgets',
        serverURL: 'http://127.0.0.1:5006', // Update to your server URL
        password: 'password'
    });

    const budgets = await api.getBudgets();
    console.log(budgets);
    
    for (const budget of budgets) {
        console.log(`Downloading budget: "${budget.name}" (ID: ${budget.id})`);
            await api.downloadBudget(budget.groupId);
        await new Promise(resolve => setTimeout(resolve, 2000)); // Wait a bit between downloads
    }

    await api.shutdown();
}

test();

Code Output Log

PS D:\DevSpace\Projects\Budgeting\actual-official\debug-api> yarn ts-node .\minimal-password-test.ts
[
  {
    cloudFileId: '447d2159-90be-4222-8eab-68584f7aeeb9',
    state: 'remote',
    groupId: 'ffa39bf4-d6fa-4044-91e8-1db772e33782',
    name: 'My Finances 1',
    encryptKeyId: null,
    hasKey: false,
    owner: '10ff7a4e-b7b6-4fa3-ad54-cdcc6a82e915',
    usersWithAccess: [ [Object] ]
  },
  {
    cloudFileId: '524592c7-64dd-4163-969f-e1d744669036',
    state: 'remote',
    groupId: 'aae4263a-6357-49f1-8a47-d3303d828ae0',
    name: 'My Finances 2',
    encryptKeyId: null,
    hasKey: false,
    owner: '10ff7a4e-b7b6-4fa3-ad54-cdcc6a82e915',
    usersWithAccess: [ [Object] ]
  }
]
Downloading budget: "My Finances 1" (ID: undefined)
Loading fresh spreadsheet
Syncing since 2025-08-01T15:47:24.504Z-0000-0000000000000000 0 (attempt: 0)
Got messages from server 0
Syncing since 1970-01-01T00:00:00.000Z-0000-0000000000000000 0 (attempt: 1)
Got messages from server 1
Downloading budget: "My Finances 2" (ID: undefined)
Loading fresh spreadsheet
[Exception] Error: App: startServices called while services are already running
    at App.startServices (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:11665:143)
    at _loadBudget (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:13482:577)      
    at async loadBudget (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:13400:49)  
    at async Object.downloadBudget [as download-budget] (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:13394:43)
    at async handlers.api/download-budget (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:11630:28)
Syncing since 2025-08-01T15:47:26.847Z-0000-0000000000000000 0 (attempt: 0)
Got messages from server 0
Syncing since 1970-01-01T00:00:00.000Z-0000-0000000000000000 0 (attempt: 1)
Got messages from server 1
Syncing since 2025-08-01T15:52:26.906Z-0000-a443de048ffdaa57 0 (attempt: 0)
Got messages from server 0

Where are you hosting Actual?

Docker

What browsers are you seeing the problem on?

Chrome, Microsoft Edge

Operating System

Windows 11

Originally created by @m-schwob on GitHub (Aug 1, 2025). ### Verified issue does not already exist? - [x] I have searched and found no existing issue ### What happened? **Description:** When using the API to download multiple budgets sequentially via `downloadBudget()`, an error `App: startServices called while services are already running` is thrown starting from the second budget. The operation still completes successfully. ### How can we reproduce the issue? **Environment:** - Actual Budget API version and Actual Server docker image version: v25.6.1 > I tried to run the minimal code using v25.7.1 it gave me "Database is out of sync with migrations" error, which I couldn't solve (might need to open another issue for it). - Authentication: password - Fresh server with two budget files - Clean dataDir folder (the minimal example does not handle the local budget case) **Minimal Code** ```ts import * as api from '@actual-app/api'; // NOTE: This test assumes: // - a server is running with 2 budgets available. // - local folder './data/budgets' is empty without previously downloaded budgets async function test() { await api.init({ dataDir: './data/budgets', serverURL: 'http://127.0.0.1:5006', // Update to your server URL password: 'password' }); const budgets = await api.getBudgets(); console.log(budgets); for (const budget of budgets) { console.log(`Downloading budget: "${budget.name}" (ID: ${budget.id})`); await api.downloadBudget(budget.groupId); await new Promise(resolve => setTimeout(resolve, 2000)); // Wait a bit between downloads } await api.shutdown(); } test(); ``` **Code Output Log** ``` PS D:\DevSpace\Projects\Budgeting\actual-official\debug-api> yarn ts-node .\minimal-password-test.ts [ { cloudFileId: '447d2159-90be-4222-8eab-68584f7aeeb9', state: 'remote', groupId: 'ffa39bf4-d6fa-4044-91e8-1db772e33782', name: 'My Finances 1', encryptKeyId: null, hasKey: false, owner: '10ff7a4e-b7b6-4fa3-ad54-cdcc6a82e915', usersWithAccess: [ [Object] ] }, { cloudFileId: '524592c7-64dd-4163-969f-e1d744669036', state: 'remote', groupId: 'aae4263a-6357-49f1-8a47-d3303d828ae0', name: 'My Finances 2', encryptKeyId: null, hasKey: false, owner: '10ff7a4e-b7b6-4fa3-ad54-cdcc6a82e915', usersWithAccess: [ [Object] ] } ] Downloading budget: "My Finances 1" (ID: undefined) Loading fresh spreadsheet Syncing since 2025-08-01T15:47:24.504Z-0000-0000000000000000 0 (attempt: 0) Got messages from server 0 Syncing since 1970-01-01T00:00:00.000Z-0000-0000000000000000 0 (attempt: 1) Got messages from server 1 Downloading budget: "My Finances 2" (ID: undefined) Loading fresh spreadsheet [Exception] Error: App: startServices called while services are already running at App.startServices (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:11665:143) at _loadBudget (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:13482:577) at async loadBudget (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:13400:49) at async Object.downloadBudget [as download-budget] (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:13394:43) at async handlers.api/download-budget (D:\DevSpace\Projects\Budgeting\actual-official\debug-api\node_modules\@actual-app\api\dist\app\bundle.api.js:11630:28) Syncing since 2025-08-01T15:47:26.847Z-0000-0000000000000000 0 (attempt: 0) Got messages from server 0 Syncing since 1970-01-01T00:00:00.000Z-0000-0000000000000000 0 (attempt: 1) Got messages from server 1 Syncing since 2025-08-01T15:52:26.906Z-0000-a443de048ffdaa57 0 (attempt: 0) Got messages from server 0 ``` ### Where are you hosting Actual? Docker ### What browsers are you seeing the problem on? Chrome, Microsoft Edge ### Operating System Windows 11
GiteaMirror added the bugAPI labels 2026-02-28 20:10:56 -06:00
Author
Owner

@matt-fidd commented on GitHub (Aug 2, 2025):

I'm pretty sure the api can only work on one budget at a time, shutting down and re-initialising the API should solve your issue.

@matt-fidd commented on GitHub (Aug 2, 2025): I'm pretty sure the api can only work on one budget at a time, shutting down and re-initialising the API should solve your issue.
Author
Owner

@m-schwob commented on GitHub (Aug 3, 2025):

It seems to work also that way, even though the error is printed. You are right that shutting down and re-initialising the API solves it, but this is why it does not make sense. If it's a real error, it should not work, and if it should work, it should not print an error.

As far as I can debug it with my limited JS experience and some help from GitHub Copilot, it appears that downloadBudget is closing the last open budget, which is why it eventually works.

From my point of view as a user, it would be expected that the API would also provide a CloseBudget function that the user can call before loading/downloading a budget. Alternatively, it will do that automatically as it seems to do now. Anyway, it makes sense that you don't have to shut down and re-initialize the API for each file since they all come from the same server and user.

BTW, I noticed in the code that there is a service handling logic when downloading a budget. With some information about that, I might be able to try to fix it. Can you give me any direction?

@m-schwob commented on GitHub (Aug 3, 2025): It seems to work also that way, even though the error is printed. You are right that shutting down and re-initialising the API solves it, but this is why it does not make sense. If it's a real error, it should not work, and if it should work, it should not print an error. As far as I can debug it with my limited JS experience and some help from GitHub Copilot, it appears that `downloadBudget` is closing the last open budget, which is why it eventually works. From my point of view as a user, it would be expected that the API would also provide a `CloseBudget` function that the user can call before loading/downloading a budget. Alternatively, it will do that automatically as it seems to do now. Anyway, it makes sense that you don't have to shut down and re-initialize the API for each file since they all come from the same server and user. BTW, I noticed in the code that there is a service handling logic when downloading a budget. With some information about that, I might be able to try to fix it. Can you give me any direction?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#2336