{"record":{"id":"02b04f93547cc1d3","repo":"actualbudget/actual","slug":"invalid-config-file-key-key-must-be-a-string","errorCode":null,"errorMessage":"Invalid config file: key \"${key}\" must be a string, got ${typeof v}","messagePattern":"Invalid config file: key \"(.+?)\" must be a string, got (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/config.ts","lineNumber":86,"sourceCode":"\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    }\n    if (\n      (numberKeys as readonly string[]).includes(key) &&\n      (typeof v !== 'number' || !Number.isInteger(v) || v < 0)\n    ) {\n      throw new Error(\n        `Invalid config file: key \"${key}\" must be a non-negative integer`,\n      );\n    }\n    if (\n      (booleanKeys as readonly string[]).includes(key) &&\n      typeof v !== 'boolean'\n    ) {\n      throw new Error(\n        `Invalid config file: key \"${key}\" must be a boolean, got ${typeof v}`,\n      );","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/cli/src/config.ts#L68-L104","documentation":"After confirming a config key is known, validateConfigFileContent checks its value type. String-typed keys (serverUrl, password, sessionToken, syncId, dataDir, encryptionPassword) must hold strings; a number, boolean, or null instead produces this error naming the key and the actual type found.","triggerScenarios":"Writing `\"cacheTtl\": ...` confusion aside, the typical case is e.g. `\"password\": 12345` (unquoted number) or `\"dataDir\": null` explicitly present; YAML configs where a value like `no: yes` coerces oddly or an unquoted port-like string becomes a number; JS config exporting `syncId: undefined` is skipped, but `syncId: 42` throws.","commonSituations":"Unquoted numeric passwords or API tokens in JSON/YAML; templating tools injecting unquoted values; hand-editing YAML where implicit typing turns \"0123\" into 123.","solutions":["Quote the value so it is a string: \"password\": \"12345\"","Remove the key entirely if the value is unknown (undefined-valued keys are skipped, absent keys are fine)","For YAML, quote values that look numeric: syncId: \"01234567\""],"exampleFix":"// before (actual.config.json)\n{ \"password\": 12345, \"dataDir\": \"./data\" }\n\n// after\n{ \"password\": \"12345\", \"dataDir\": \"./data\" }","handlingStrategy":"type-guard","validationCode":"const STRING_KEYS = ['serverUrl','password','sessionToken','syncId','dataDir','encryptionPassword'];\nfor (const k of STRING_KEYS) {\n  if (cfg[k] !== undefined && typeof cfg[k] !== 'string') {\n    throw new Error(`Config key \"${k}\" must be a string (quote numeric-looking values)`);\n  }\n}","typeGuard":"function stringsAreStrings(v: Record<string, unknown>, keys: readonly string[]): boolean {\n  return keys.every(k => v[k] === undefined || typeof v[k] === 'string');\n}","tryCatchPattern":"try {\n  await run(['actual', 'accounts']);\n} catch (e) {\n  if (String(e.message).includes('must be a string')) {\n    console.error('Quote the named key\\'s value in your config file so it parses as a string');\n  } else throw e;\n}","preventionTips":["Always quote password, token, and syncId values in JSON/YAML — even numeric-looking ones","In YAML, quote values that could be implicitly typed (e.g. syncId: \"01234567\")","If a templating tool writes the config, render values inside quotes"],"tags":["cli","config","type-error","validation"],"backgroundTag":"invalid-config-file","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}