actualbudget/actual · error · Error

Authentication required. Provide --password or --session-tok

Error message

Authentication required. Provide --password or --session-token, or set ACTUAL_PASSWORD / ACTUAL_SESSION_TOKEN.

What it means

withConnection wraps every data command; it builds the runtime configuration and refuses to proceed without credentials. When neither password-based nor session-token-based authentication is configured (CLI flag, env var, or config file), it throws this error instead of attempting a doomed connection. This is a fail-fast guard mirroring resolveConfig's auth requirement at the command layer.

Source

Thrown at packages/cli/src/connection.ts:64

  info(`Connecting to ${config.serverUrl}...`, globalOpts.verbose);

  if (config.sessionToken) {
    await api.init({
      serverURL: config.serverUrl,
      dataDir: config.dataDir,
      sessionToken: config.sessionToken,
      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,

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Export ACTUAL_PASSWORD or ACTUAL_SESSION_TOKEN before running the command.
  2. Pass --password or --session-token directly to the command.
  3. Store credentials in the config file and confirm that config file is the one loaded.
  4. Print/inspect the resolved environment in CI (`env | grep ACTUAL`) to confirm the secrets exist.

Example fix

// before
$ actual-cli accounts --sync-id $ID
Error: Authentication required...
// after
$ export ACTUAL_SESSION_TOKEN=...
$ actual-cli accounts --sync-id $ID
Defensive patterns

Strategy: validation

Validate before calling

if (!process.env.ACTUAL_PASSWORD && !process.env.ACTUAL_SESSION_TOKEN) {
  throw new Error('Set ACTUAL_PASSWORD or ACTUAL_SESSION_TOKEN before running CLI commands.');
}

Type guard

function hasAuth(o: { password?: string; sessionToken?: string }): boolean {
  return typeof o.password === 'string' && o.password.length > 0 ||
         typeof o.sessionToken === 'string' && o.sessionToken.length > 0;
}

Try / catch

try {
  await withConnection(opts, fn);
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Authentication required')) {
    console.error('No credentials found: pass --password/--session-token or export ACTUAL_PASSWORD/ACTUAL_SESSION_TOKEN.');
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: Running any accounts/budgets/categories/payees/query command where config lacks both password and sessionToken across --password/--session-token flags, ACTUAL_PASSWORD/ACTUAL_SESSION_TOKEN, and config file entries.

Common situations: Interactive shell without the env vars exported (set in a different terminal or only in .bashrc after su); CI job missing secrets; typo'd env var names.

Understand the failure class

Related errors


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