actualbudget/actual · error · Error

Failed to copy SQL file from ${frompath} to ${topath}: ${sec

Error message

Failed to copy SQL file from ${frompath} to ${topath}: ${secondError.message}

What it means

`copyFile` first tries a regular write-based copy; when either path is a `.sqlite` database it falls back to `_copySqlFile` (SQL dump/re-import). If that fallback also fails, the underlying error is rethrown with full source/destination context.

Source

Thrown at packages/loot-core/src/platform/server/fs/index.ts:393

export const size = async function (filepath) {
  const attrs = FS.stat(resolveLink(filepath));
  return attrs.size;
};

export const copyFile = async function (
  frompath: string,
  topath: string,
): Promise<boolean> {
  let result = false;
  try {
    const contents = await _readFile(frompath);
    result = await _writeFile(topath, contents);
  } catch (error) {
    if (frompath.endsWith('.sqlite') || topath.endsWith('.sqlite')) {
      try {
        result = await _copySqlFile(frompath, topath);
      } catch (secondError) {
        throw new Error(
          `Failed to copy SQL file from ${frompath} to ${topath}: ${secondError.message}`,
        );
      }
    } else {
      throw error;
    }
  }
  return result;
};

export async function readFile(
  filepath: string,
  encoding?: 'utf8',
): Promise<string>;
export async function readFile(
  filepath: string,
  encoding: 'binary',
): Promise<Uint8Array>;

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Read the inner `secondError.message` in the thrown text — it names the actual failing step (read vs write)
  2. Verify the source `.sqlite` opens correctly (e.g. try loading the budget) and repair or restore from backup if corrupt
  3. Check free storage/quota and write permissions for the destination path
  4. Retry the copy after closing other connections to the database
Defensive patterns

Strategy: retry

Validate before calling

import { exists } from './platform/server/fs';
if (!(await exists(frompath))) throw new Error(`Source missing: ${frompath}`);
// ensure destination dir is writable before copying

Try / catch

try {
  await fs.copyFile(from, to);
} catch (e) {
  if (String(e).startsWith('Failed to copy SQL file')) {
    // parse inner error; verify source DB integrity, free space, then retry once
  } else throw e;
}

Prevention

When it happens

Trigger: `copyFile(frompath, topath)` where a path ends in `.sqlite` and `_copySqlFile` throws — corrupt source DB, failed export, or a failed write of the destination SQL file.

Common situations: Duplicating or backing up a budget while the database is locked/corrupt; destination path unwritable (quota exceeded, permission error); interrupted earlier write leaving a broken sqlite file.

Related errors


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