actualbudget/actual · error · Error

Invalid config file: unknown key "${key}"

Error message

Invalid config file: unknown key "${key}"

What it means

When validating the CLI config file, every key present must be one of the recognized option names (serverUrl, password, sessionToken, syncId, dataDir, encryptionPassword, cacheTtl, lockTimeout, noLock). Any unknown key causes this error, so typos and renamed options are caught immediately instead of being silently ignored.

Source

Thrown at packages/cli/src/config.ts:78

  noLock?: boolean;
};

const configFileKeys: readonly string[] = [
  ...stringKeys,
  ...numberKeys,
  ...booleanKeys,
];

function validateConfigFileContent(value: unknown): ConfigFileContent {
  if (!isRecord(value)) {
    throw new Error(
      'Invalid config file: expected an object with keys: ' +
        configFileKeys.join(', '),
    );
  }
  for (const key of Object.keys(value)) {
    if (!configFileKeys.includes(key)) {
      throw new Error(`Invalid config file: unknown key "${key}"`);
    }
    const v = value[key];
    if (v === undefined) continue;
    if (
      (stringKeys as readonly string[]).includes(key) &&
      typeof v !== 'string'
    ) {
      throw new Error(
        `Invalid config file: key "${key}" must be a string, got ${typeof v}`,
      );
    }
    if (
      (numberKeys as readonly string[]).includes(key) &&
      (typeof v !== 'number' || !Number.isInteger(v) || v < 0)
    ) {
      throw new Error(
        `Invalid config file: key "${key}" must be a non-negative integer`,
      );

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Remove or rename the offending key to one of: serverUrl, password, sessionToken, syncId, dataDir, encryptionPassword, cacheTtl, lockTimeout, noLock
  2. Check the error message — it names the exact unknown key; fix its casing/spelling
  3. If the option belongs to the sync-server, move it to the server's own config file
  4. Consult the CLI docs for your installed version to see current valid keys

Example fix

// before (actual.config.json)
{ "serverurl": "http://localhost:5006", "dataDir": "./data" }

// after
{ "serverUrl": "http://localhost:5006", "dataDir": "./data" }
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = ['serverUrl','password','sessionToken','syncId','dataDir','encryptionPassword','cacheTtl','lockTimeout','noLock'];
for (const k of Object.keys(cfg)) {
  if (!ALLOWED.includes(k)) throw new Error(`Unknown CLI config key "${k}"`);
}

Type guard

function onlyKnownKeys(v: Record<string, unknown>, allowed: readonly string[]): boolean {
  return Object.keys(v).every(k => allowed.includes(k));
}

Try / catch

try {
  await run(['actual', 'accounts']);
} catch (e) {
  if (String(e.message).includes('unknown key')) {
    const key = /unknown key "(.+?)"/.exec(String(e.message))?.[1];
    console.error(`Remove or rename "${key}" in your config file`);
  } else throw e;
}

Prevention

When it happens

Trigger: A config file containing `syncId` misspelled as `syncID` or `sync-id`; leftover keys from an older CLI version (e.g. removed options); keys meant for the sync-server config (like `serverFiles` or `port`) placed in the CLI config; camelCase mistakes such as `serverurl` or `data-dir`.

Common situations: Merging server config examples into the CLI config; upgrading/downgrading and carrying deprecated keys; documentation drift between versions.

Related errors


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