{"record":{"id":"634cae007cce04db","repo":"actualbudget/actual","slug":"failed-to-copy-sql-file-from-frompath-to-topa","errorCode":null,"errorMessage":"Failed to copy SQL file from ${frompath} to ${topath}: ${secondError.message}","messagePattern":"Failed to copy SQL file from (.+?) to (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/loot-core/src/platform/server/fs/index.ts","lineNumber":393,"sourceCode":"export const size = async function (filepath) {\n  const attrs = FS.stat(resolveLink(filepath));\n  return attrs.size;\n};\n\nexport const copyFile = async function (\n  frompath: string,\n  topath: string,\n): Promise<boolean> {\n  let result = false;\n  try {\n    const contents = await _readFile(frompath);\n    result = await _writeFile(topath, contents);\n  } catch (error) {\n    if (frompath.endsWith('.sqlite') || topath.endsWith('.sqlite')) {\n      try {\n        result = await _copySqlFile(frompath, topath);\n      } catch (secondError) {\n        throw new Error(\n          `Failed to copy SQL file from ${frompath} to ${topath}: ${secondError.message}`,\n        );\n      }\n    } else {\n      throw error;\n    }\n  }\n  return result;\n};\n\nexport async function readFile(\n  filepath: string,\n  encoding?: 'utf8',\n): Promise<string>;\nexport async function readFile(\n  filepath: string,\n  encoding: 'binary',\n): Promise<Uint8Array>;","sourceCodeStart":375,"sourceCodeEnd":411,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/loot-core/src/platform/server/fs/index.ts#L375-L411","documentation":"`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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Read the inner `secondError.message` in the thrown text — it names the actual failing step (read vs write)","Verify the source `.sqlite` opens correctly (e.g. try loading the budget) and repair or restore from backup if corrupt","Check free storage/quota and write permissions for the destination path","Retry the copy after closing other connections to the database"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"import { exists } from './platform/server/fs';\nif (!(await exists(frompath))) throw new Error(`Source missing: ${frompath}`);\n// ensure destination dir is writable before copying","typeGuard":null,"tryCatchPattern":"try {\n  await fs.copyFile(from, to);\n} catch (e) {\n  if (String(e).startsWith('Failed to copy SQL file')) {\n    // parse inner error; verify source DB integrity, free space, then retry once\n  } else throw e;\n}","preventionTips":["Avoid copying .sqlite files while the budget is open/locked","Check storage quota before large DB copies","Back up budgets through the app's export feature instead of raw file copies"],"tags":["fs","sqlite","copy-failure"],"backgroundTag":"file-copy-failed","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}