actualbudget/actual · error
File does not appear to be a valid qif file: ${line}
Error message
File does not appear to be a valid qif file: ${line} What it means
qif2json requires the first line of a QIF file to be a type header of the form '!Type:Bank' (or similar). If the first line is empty or does not match the expected type pattern, the parser cannot determine the account type and throws this error including the offending line.
Source
Thrown at packages/loot-core/src/server/transactions/import/qif2json.ts:38
};
export function qif2json(qif, options: { dateFormat?: string } = {}) {
const lines = qif.split('\n').filter(Boolean);
let line = lines.shift();
const type = /!Type:([^$]*)$/.exec(line.trim());
const data: {
dateFormat: string | undefined;
type?;
transactions: QIFTransaction[];
} = {
dateFormat: options.dateFormat,
transactions: [],
};
const transactions = data.transactions;
let transaction: QIFTransaction = {};
if (!type || !type.length) {
throw new Error('File does not appear to be a valid qif file: ' + line);
}
data.type = type[1];
let division: Division = {};
while ((line = lines.shift())) {
line = line.trim();
if (line === '^') {
transactions.push(transaction);
transaction = {};
continue;
}
switch (line[0]) {
case 'D':
transaction.date = line.substring(1);
break;
case 'T':
transaction.amount = line.substring(1);View on GitHub (pinned to d4334cb6e6)
Solutions
- Open the file and verify the very first non-empty line starts with '!Type:' (e.g. '!Type:Bank').
- Strip any UTF-8 BOM and leading blank lines before parsing.
- Confirm the file is actually QIF format, not CSV/OFX renamed to .qif; re-export from the bank in QIF format.
- Trim leading whitespace/newlines from the file content before passing it to parseQIF.
Example fix
// before
const data = qif2json.parse(rawFileContents);
// after
const cleaned = rawFileContents.replace(/^\uFEFF/, '').replace(/^\s+/, '');
if (!/^!Type:/im.test(cleaned.split(/\r?\n/, 1)[0])) {
throw new Error('Missing !Type header — not a valid QIF file');
}
const data = qif2json.parse(cleaned); Defensive patterns
Strategy: validation
Validate before calling
const firstLine = content.replace(/^\uFEFF/, '').split(/\r?\n/, 1)[0];
if (!/^!Type:/i.test(firstLine.trim())) {
throw new Error('Not a QIF file: missing !Type header on first line');
} Type guard
function isQifContent(content: string): boolean {
const first = content.replace(/^\uFEFF/, '').trimStart().split(/\r?\n/, 1)[0];
return /^!Type:/i.test(first);
} Try / catch
try {
const data = parseQIF(file);
} catch (e) {
if (e.message.startsWith('File does not appear to be a valid qif file')) {
showError('This file is not a valid QIF export. Check the first line is !Type:...');
} else { throw e; }
} Prevention
- Strip BOM and leading whitespace before parsing
- Verify the first line matches /^!Type:/i before importing
- Confirm the file extension and content both indicate QIF, not CSV/OFX
When it happens
Trigger: Importing a file whose first line is blank, whose '!Type' header is misspelled (e.g. '!TYPE:Bank' with wrong capitalization is fine but '!Type' missing entirely is not), a file exported with a BOM or leading whitespace, or passing a non-QIF file (CSV, OFX) to parseQIF.
Common situations: Bank exports that prepend metadata lines before the !Type header; files saved with UTF-8 BOM by Windows tools; users renaming a CSV to .qif; truncated downloads missing the header.
Related errors
- Unknown Detail Code: ${line[0]}
- Error importing budget: ${result.error}
- Error importing budget: no budget was loaded
- zipMeta ? getUnsafeZipError(zipMeta) : error
- An error occurred while parsing the template
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/9e884fbd9dd21c70.
Report an issue: GitHub.