{"record":{"id":"d7719be47b283000","repo":"actualbudget/actual","slug":"invalid-config-file-expected-an-object-with-keys","errorCode":null,"errorMessage":"Invalid config file: expected an object with keys: ${configFileKeys.join(', ')}","messagePattern":"Invalid config file: expected an object with keys: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/config.ts","lineNumber":71,"sourceCode":"  password?: string;\n  sessionToken?: string;\n  syncId?: string;\n  dataDir?: string;\n  encryptionPassword?: string;\n  cacheTtl?: number;\n  lockTimeout?: number;\n  noLock?: boolean;\n};\n\nconst configFileKeys: readonly string[] = [\n  ...stringKeys,\n  ...numberKeys,\n  ...booleanKeys,\n];\n\nfunction validateConfigFileContent(value: unknown): ConfigFileContent {\n  if (!isRecord(value)) {\n    throw new Error(\n      'Invalid config file: expected an object with keys: ' +\n        configFileKeys.join(', '),\n    );\n  }\n  for (const key of Object.keys(value)) {\n    if (!configFileKeys.includes(key)) {\n      throw new Error(`Invalid config file: unknown key \"${key}\"`);\n    }\n    const v = value[key];\n    if (v === undefined) continue;\n    if (\n      (stringKeys as readonly string[]).includes(key) &&\n      typeof v !== 'string'\n    ) {\n      throw new Error(\n        `Invalid config file: key \"${key}\" must be a string, got ${typeof v}`,\n      );\n    }","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/cli/src/config.ts#L53-L89","documentation":"The Actual CLI loads its configuration from a config file via cosmiconfig and validates it with validateConfigFileContent. The file's top level must be a JSON/YAML object whose keys are all from the known set (serverUrl, password, sessionToken, syncId, dataDir, encryptionPassword, cacheTtl, lockTimeout, noLock). A top-level array, string, or null is rejected with this error listing the allowed keys.","triggerScenarios":"A .actual-cli-config.json / actual.config.json containing an array or a bare string; a file that is empty or contains only a comment; YAML files where the top level is a list; a file holding credentials in a nested structure like { \"config\": {...} }.","commonSituations":"Copying an example into the wrong file; tools generating config as an array of profiles; accidental overwrite of the config with output of another command.","solutions":["Make the top level a flat object with only the supported keys, e.g. { \"serverUrl\": \"http://localhost:5006\", \"dataDir\": \"./data\" }","Flatten nested wrappers — remove any surrounding { \"config\": ... } or [ ... ] structure","Check what file cosmiconfig picked up (actual.config.js, .actualclirc, etc.) and inspect its exports","If the file is a JS config, ensure it module.exports an object, not a function or array"],"exampleFix":"// before (actual.config.js)\nmodule.exports = [\n  { serverUrl: 'http://localhost:5006' }\n];\n\n// after\nmodule.exports = {\n  serverUrl: 'http://localhost:5006',\n  dataDir: './data'\n};","handlingStrategy":"type-guard","validationCode":"const cfg = JSON.parse(readFileSync(configPath, 'utf8'));\nif (cfg === null || typeof cfg !== 'object' || Array.isArray(cfg)) {\n  throw new Error(`${configPath} must be a flat object of CLI options`);\n}","typeGuard":"function isConfigObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v);\n}","tryCatchPattern":"try {\n  await run(['actual', 'query', 'transactions']);\n} catch (e) {\n  if (String(e.message).includes('Invalid config file')) {\n    console.error(`Fix ${configPath}: top level must be an object with only CLI option keys`);\n  } else throw e;\n}","preventionTips":["Keep the config a flat object; no arrays, wrappers, or profiles","Run `jq type` / `node -e` validation after regenerating config files","Keep server options in the sync-server's config, not the CLI's"],"tags":["cli","config","json","validation"],"backgroundTag":"invalid-config-file","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}