actualbudget/actual · error · Error
throw Error(errorMsg)
Error message
throw Error(errorMsg)
What it means
During YNAB5 budget import, schedule creation retries with a suffixed name ('Name (1)', 'Name (2)') when a schedule with the same name exists. If the api/schedule-create call keeps failing after MAX_RETRY attempts, the last error is normalized and rethrown as a plain Error. This means the import could not create a schedule even after de-duplication attempts, so the failure is usually not about the name at all.
Source
Thrown at packages/loot-core/src/server/importers/ynab5.ts:890
payee: string;
account: string;
amount: number;
amountOp: 'is';
date: RecurConfig | string;
}) {
const baseName = params.name;
let count = 1;
while (true) {
try {
return await send('api/schedule-create', {
...params,
name: params.name,
});
} catch (e) {
if (count >= MAX_RETRY) {
const errorMsg = normalizeError(e);
throw Error(errorMsg);
}
params.name = `${baseName} (${count})`;
count += 1;
}
}
}
async function getRuleForSchedule(
scheduleId: string,
): Promise<RuleEntity | null> {
const { data: ruleId } = (await send('api/query', {
query: q('schedules')
.filter({ id: scheduleId })
.calculate('rule')
.serialize(),
})) as { data: string | null };
if (!ruleId) {
return null;View on GitHub (pinned to d4334cb6e6)
Solutions
- Inspect the normalized error message to find the real cause — it is the underlying schedule-create failure, not a name collision
- Validate the YNAB file's scheduled transaction date/recurrence data before import
- Check that the referenced payee and account were successfully imported and exist
- Retry the import after fixing the budget file; if it persists, file an issue with the schedule payload
Example fix
// before (retry loop rethrows opaque error)
if (count >= MAX_RETRY) {
const errorMsg = normalizeError(e);
throw Error(errorMsg);
}
// after (preserve cause and context)
if (count >= MAX_RETRY) {
throw new Error(
`Failed to create schedule "${baseName}" after ${count} attempts: ${normalizeError(e)}`,
{ cause: e },
);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check for an existing schedule with the same name before import
const existing = await send('api/query', {
query: q('schedules').filter({ name: scheduleName }).select('id'),
});
if (existing.data.length > 0) console.warn(`Schedule "${scheduleName}" exists; importer will rename`); Type guard
function isRetryableScheduleError(e: unknown): boolean {
const msg = e instanceof Error ? e.message : String(e);
return /already exists|duplicate/i.test(msg);
} Try / catch
try {
await doYnab5Import(buffer);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (/schedule/i.test(msg)) {
console.error('Schedule import failed:', msg); // inspect underlying cause
} else {
throw e;
}
} Prevention
- Validate the YNAB export's scheduled transaction recurrence data before importing
- Ensure payees/accounts referenced by schedules import successfully (they are created earlier in the pipeline)
- Uniquify schedule names in the source file to avoid exercising the retry path
- Check the underlying error message — name collision is auto-handled, so failure means a deeper validation problem
When it happens
Trigger: createScheduleWithUniqueName calls send('api/schedule-create', ...) and the call throws MAX_RETRY consecutive times: e.g. invalid recurring date config (bad RecurConfig from the YNAB file), invalid payee/account ids, or a persistent server-side validation error that does not disappear when the name changes.
Common situations: Importing a YNAB budget whose scheduled transaction has a malformed or unsupported recurrence pattern; corrupted ids referenced by the schedule; a bug/regression in schedule-create validation rejecting the payload regardless of name.
Related errors
- Unsupported scheduled frequency: ${frequency}
- Either `filepath` or `buffer` must be given
- Invalid dashboard.widgets data type: it must be an array of
- Invalid widget.${idx}.x data-type for value ${widget.x}.
- Invalid widget.${idx}.y data-type for value ${widget.y}.
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/4379feb1b7f0f109.
Report an issue: GitHub.