actualbudget/actual · error · Error
Sync ID is required for this command. Set --sync-id or ACTUA
Error message
Sync ID is required for this command. Set --sync-id or ACTUAL_SYNC_ID.
What it means
withConnection requires a sync id for any command that operates on a budget (i.e. when skipBudget is false). After the auth check, if config.syncId is falsy it throws this error, because the command cannot know which budget file to lock, open, and sync.
Source
Thrown at packages/cli/src/connection.ts:72
verbose: globalOpts.verbose,
});
} else if (config.password) {
await api.init({
serverURL: config.serverUrl,
dataDir: config.dataDir,
password: config.password,
verbose: globalOpts.verbose,
});
} else {
throw new Error(
'Authentication required. Provide --password or --session-token, or set ACTUAL_PASSWORD / ACTUAL_SESSION_TOKEN.',
);
}
try {
if (skipBudget) return await fn(config);
if (!config.syncId) {
throw new Error(
'Sync ID is required for this command. Set --sync-id or ACTUAL_SYNC_ID.',
);
}
const meta = getMetaDir(config.dataDir, config.syncId);
let release: Release | null = null;
if (!config.noLock) {
release = mutates
? await acquireExclusive(meta, {
timeoutMs: config.lockTimeout * 1000,
})
: await acquireShared(meta, {
timeoutMs: config.lockTimeout * 1000,
});
}
try {
const cachedState = readCacheState(meta);View on GitHub (pinned to d4334cb6e6)
Solutions
- Pass --sync-id <id> to the command (the budget's groupId or cloudFileId).
- Export ACTUAL_SYNC_ID in the environment or CI secrets.
- Add syncId to the config file if you always work with the same budget.
- Run the budgets command first to discover available sync ids.
Example fix
// before
actual-cli transactions --data '{...}'
// after
actual-cli transactions --sync-id "$ACTUAL_SYNC_ID" --data '{...}' Defensive patterns
Strategy: validation
Validate before calling
const syncId = cliOpts.syncId ?? process.env.ACTUAL_SYNC_ID;
if (!syncId) {
throw new Error('A sync id is required: pass --sync-id or export ACTUAL_SYNC_ID.');
} Type guard
function hasSyncId(c: { syncId?: string }): c is typeof c & { syncId: string } {
return typeof c.syncId === 'string' && c.syncId.length > 0;
} Try / catch
try {
await withConnection(opts, fn);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Sync ID is required')) {
console.error('Pass --sync-id (budget groupId/cloudFileId) or set ACTUAL_SYNC_ID.');
process.exit(1);
}
throw err;
} Prevention
- Set ACTUAL_SYNC_ID in shell profiles/CI for the default budget.
- Discover ids with the budgets listing command and persist them in your config file.
- Guard wrapper scripts with `[ -n "$ACTUAL_SYNC_ID" ] || exit 1`.
- Remember only commands that operate on a budget need it.
When it happens
Trigger: Running accounts/budgets/categories/payees/query commands without --sync-id and without ACTUAL_SYNC_ID set; only commands that skip budget loading (skipBudget) may omit it.
Common situations: New users assuming the CLI auto-detects the single local budget; scripts migrated from an API-only workflow where the budget id was passed differently; env var not exported inside a subshell/CI step.
Related errors
- Server URL is required. Set --server-url, ACTUAL_SERVER_URL
- Invalid config file: expected an object with keys: ${configF
- Invalid config file: unknown key "${key}"
- Invalid config file: key "${key}" must be a string, got ${ty
- Invalid config file: key "${key}" must be a non-negative int
AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29).
Data as JSON: /api/errors/6b54a74cd6f06c45.
Report an issue: GitHub.