What happened?
On an Alpine/musl Node image, @actual-app/api's downloadBudget() fails at the binary sync step (postBinary to POST /sync/sync) with PostError: network-failure. The identical setup on a Debian Slim Node image works. Same Node 22, same package, same self-hosted server.
try {
const res = await fetch(url, { // Node global fetch (undici)
method: "POST",
body: Buffer.from(data),
headers: {
"Content-Length": data.length, // hand-set, and a NUMBER
"Content-Type": "application/actual-sync",
...headers,
},
});
} catch { // bare catch — original error discarded
throw new PostError("network-failure");
}
Suggested fixes
- Don't set Content-Length manually in postBinary and let fetch derive it from the body.
- Catch the cause so it's diagnosable:
How can we reproduce the issue?
- @actual-app/api 26.6.0, actual-server 26.6.0, alpline container (Node 22)
- Run a normal api.init({ serverURL, password, dataDir }) + api.downloadBudget(syncId) script.
- In a alpine container: login + all /sync/* GET succeeds, then download-budget throws:
PostError: network-failure
at postBinary (@actual-app/api/dist/index.js)
at _fullSync → initialFullSync → syncBudget → download-budget
- The same script in a Debian Node 22 container → POST 200 /sync/sync, sync completes.
Where are you hosting Actual?
Docker
What browsers are you seeing the problem on?
Other
Operating System
Linux
What happened?
On an Alpine/musl Node image, @actual-app/api's downloadBudget() fails at the binary sync step (postBinary to POST /sync/sync) with PostError: network-failure. The identical setup on a Debian Slim Node image works. Same Node 22, same package, same self-hosted server.
Suggested fixes
How can we reproduce the issue?
Where are you hosting Actual?
Docker
What browsers are you seeing the problem on?
Other
Operating System
Linux